原型继承和应用
来源:互联网 发布:unity3d小游戏源代码 编辑:程序博客网 时间:2024/05/04 21:22
原型继承是js的一种继承方式,原型继承是什么意思呢,其实就是说构造函数和子构造函数,或者说类和子类之间(当然js中不存在类),唯一的继承传递方式是通过原型,而不是其他语言直接通过extends(当然ES6的语法糖出现了extends)。所以你需要手写prototype。(封装手写prototype的方法请看我的另一篇文章详解js中extend函数) 我们先看一个简单的例子
function Parent(){ this.job = 'teacher'; } Parent.prototype.showJob = function(){ alert(this.job); } var child = new Parent(); child.showJob(); //'teacher'
很明显,这个例子中的child获得属性job和一个方法showJob,为什么会获得呢? 这时候来看看new Parent()到底做了什么
var obj = { }; //obj获得Parent的this引用 obj.job = 'teacher'; obj.__proto__ = Parent.prototype; var child = obj;
所以为什么child获得了属性job,是因为他执行了构造函数,child对象上获得了属性job。而为什么child获得了方法showJob, 是因为对象上有一个隐藏的原型__proto__ ,它指向了Parent.prototype。当我们在对象child上调用方法时,它首先检查对象自己是否具有这个方法,没有的话搜索自己的隐藏原型中有没有这个方法,所以当一个对象上有方法,它要么存在于自身中,要么存在于隐式原型中,要实现原型长链的继承,只能从隐式原型上想办法。
所以,原型继承是什么,它的本质是改变其他对象的__proto__,或者说让它丰富起来,以获得父构造函数或者祖先构造函数的方法,请看代码。
function Parent(){ } Parent.prototype.showJob = function(){} function Child(){ } Child.prototype = new Parent(); Child.prototype.constructor = Child; var grandChild = new Child();
这时候grandChild获得了showJob方法,因为它的__proto__中有showJob方法,而为什么它的隐式原型中有这个方法呢,因为new Child()中grandChild.__proto__指向了Child的prototype, 至于为什么Child的prototype中有showJob方法,因为Child.prototype.__proto__等于Parent.prototype.
至于为什么有这么一句
Child.prototype.constructor = Child;
这是因为原本Child.prototype中有一个constructor属性指向Child本身,当执行Child.prototype = new Parent()的时候,Child.prototype.constructor指向了Parent,否则下一次new Child的时候,constructor的指向就会不正确,当然,这个在实际开发中即时漏掉也不会有大问题,因为我们很少会对constructor进行读写。
以上代码还有另一个问题,为什么我们要把showJob这个方法写在Parent.prototype上呢,如果写成如下
function Parent(){ this.showJob = function(){} } function Child(){ } Child.prototype = new Parent();
当然这样写也可以,child.prototype对象上有了showJob方法,而不是child.prototype.__proto__,这对于我们原型链的继承并没有影响。然而这样写的方法一多,child.prototype对象上的方法就越多,如果new了多次的话,在内存上会比写在原型上多一些消耗。
那么在实际开发中,会怎么实现面向对象的原型继承呢。正常在我们拿到需求的时候,如果需求逻辑复杂,且在多个页面中有相似逻辑的时候,我们就会想到使用面向对象了,因为面向对象解决的就是逻辑的封装和复用。
假设页面A,页面B,页面C中存在相同逻辑,那么我们可以封装父构造函数对象
function Parent(){} Parent.prototype = { method1: function(){}, method2: function(){}, ... } function A(){ //页面A this.A = A; } A.prototype = new Parent(); A.prototype.otherMethod = function(){}; var a = new A(); //使用对象 a.init...
首先将页面A,页面B,页面C中相同逻辑抽离,相同逻辑可以是同一个ajax请求返回数据,或者是数据格式化等等的相同操作。将这些方法在Parent.prototype中定义,至于A,B,C页面自己特有的方法,则在如A.prototype中定义。这样很好地了解决了我们的问题,逻辑清晰,代码复用性强。
如果在Parent方法参数中加入了回调callback,并且在callback中想调用子函数方法或者属性,可以参考我另一篇博文call和apply上手分析
hasOwnProperty
hasOwnProperty方法可以检测一个属性是存在于实例中,还是存在于原型中。
function Parent(){ this.name = 'sysyzhyupeng'; } Parent.prototype.job = 'teacher'; Parent.prototype.showJob = function(){ } var parent = new Parent(); parent.hasOwnProperty('name'); // true parent.hasOwnProperty('job'); // false //方法也可以 parent.hasOwnProperty('showJob'); // false
in
in运算符和hasOwnProperty不同,只要存在在原型上或者对象上就返回true
function Parent(){ this.name = 'sysyzhyupeng'; } Parent.prototype.job = 'teacher'; Parent.prototype.showJob = function(){ } var parent = new Parent(); 'name' in parent; // true 'job' in parent // true for(_key in parent){ console.log(_key); // 'name', 'job', 'showJob' }
在使用for-in循环时,返回的是所有能通过对象访问的且可枚举的属性。所有开发人正常定义的属性都是可枚举的,只有在IE8及更早版本除外。
Object.keys
ES5的Object.keys方法可以返回对象上的所有可枚举属性(注意只有对象上的,从原型上继承的没有)
- 原型继承和应用
- 原型和原型链继承
- 原型继承和Class继承
- 原型对象和继承
- JavaScript原型和继承
- JavaScript原型和继承
- Javascript原型和继承
- JavaScript原型和继承
- JavaScript 原型和继承
- JS原型和继承
- JavaScript原型和继承
- Js 原型和继承
- JavaScript原型和继承
- 原型和继承
- 原型和继承
- JavaScript原型和继承
- javascript原型和继承
- 继承和原型链
- 简单的方式解决跨域问题
- go学习笔记-工作区和代码包
- 抽象类 & 接口
- 五类IP地址的划分
- java-字符串比较
- 原型继承和应用
- Surround 360:环境配置与实例测试
- 2017年1月20日参加培训-《如何做好向上汇报》
- qml 实现文本编辑器
- ural 1106
- spark graphx图计算常用操作实战
- 自定义指令
- 东北工学院建校始末
- 将近年关,写写吧