javascript原型继承学习笔记
2009-05-29 11:13
656 查看
在谈Js之前,首先需要明确几个概念:
1.某一对象的原型仍是一个对象.
2.js原型继承的实质是复制,但也不是完全复制,而是子对象更改了什么数据,就复制什么数据.具体做法为创建一张成员维护表.如:
function Parent(b) { this.a = "a"; this.b = b==null ? "b" : b; };function Child(b) { Parent.call(this,b); }; Child.prototype = new Parent(); var c = new Child(); alert(c.b)
3.当需要查找某个属性时,首先读对象实例自己维护的表.如果没有找到指定的成员,就要遍历整个原型链,直到原型为空的对象({}),或者到找到该成员为止。 4.每个函数都有一个prototype属性指向其原型对象,默认为{},即空对象. 5.每个对象都有一个constructor属性,默认指向本对象的构造函数(这句话没有讲完,请接看往下看) 6.Objcet对象的prototype属性是空对象{},空对象的constructor属性指向Object函数构造,所以所有对象的总原型都是Object(参见第4条) 7.对于new操作符,比如:
function Parent(b) { this.a = "a"; this.b = b==null ? "b" : b; };对于:
var p = new Person("c");其实可以写成这样:
var p = {}; Person.call(p,"c");这就很明白了,其实首先是创建了一个空对象,然后将这个对象以this参数传入构造函数Person,于是Person对象就new出来了. 好了,下面来说正题.上图: 其实这是别人画的一张图,画的很好,我就拿来主义了,呵呵.代码如下:
function MyObject() { this.constructor = arguments.callee; //正确维护constructor,以便回溯外部原型链 } MyObject.prototype = new Object(); //人为构建外部原型链 function MyObjectEx() { this.constructor = arguments.callee; //正确维护constructor,以便回溯外部原型链 } MyObjectEx.prototype = new MyObject(); //人为构建外部原型链 obj1 = new MyObjectEx(); obj2 = new MyObjectEx(); alert(obj1.constructor === MyObjectEx); //true alert(MyObjectEx.prototype instanceof MyObject); //true alert(MyObjectEx.prototype.constructor === MyObject); //true alert(MyObject.prototype instanceof Object); //true alert(MyObject.prototype.constructor === Object); //true alert(obj1.constructor.prototype.constructor.prototype.constructor === Object); //true,完成了所有的回溯
学习JS的原型继承,最重要的就是搞清楚JS的原型链.
所谓原型链,就是一条记录了JS对象继承过程的链表,而其组成部分就是每个对象的constructor属性与函数的prototype属性.通过对象的constructor属性可以找到本对象的构造构数,通过构造构数prototype属性又可以找到其上一级的对象.就这样一级一级的回溯,直到Object. 还有一条隐藏的原型链,通过.proto属性维护,不过这是系统自行维护的,不需要人为参与,也不可见,虽然firefox浏览可以访问,但还是不推荐. 看似简单,但是陷阱很多,如下:function Parent(){}; function Child(){}; Child.prototype = new Parent(); var p = new Parent(); var c = new Child(); alert(p.constructor == c.constructor) //truep与c明明一个是基对象,一个是子对象,怎么会p.constructor == c.constructor呢? 当你alert(p.constructor),显示的是Person(),但当你alert(c.constructor)时,打印的还是Person(),这就奇怪了,c的constructor不是Child()吗? 原因就是第三行代码:
Child.prototype = new Parent();文章开始时的第5条说过:每个对象都有一个constructor属性,默认指向本对象的构造函数,其实这句话没有说完:每个对象的prototype对象的constructor属性默认也指向本构造函数,但是,当你改变了其prototype所指对象后,情况就有点不同了,如上例,当指向Parent后,原型对象的constructor会指向Person,这是对的,然而,由于原型继承的本质是复制,会把这个属性值复制过来,会改变本对象的constructor属性,让其也指向Person. 但是,如果代码这样写,结果就不同了:
function Parent(){}; function Child(){}; var p = new Parent(); var c = new Child(); Child.prototype = new Parent(); alert(p.constructor == c.constructor) //false我把它从第三行放到第五行.结果就是false了,原因是我先new对象,再更改原型.其实在对象被new出来之后,就与构造函数无关了,更改构造函数不会影响到已new出来的对象. 但是这样写的很少,因为这不符合面向对象的原则.回到刚才的话题,怎么才能在先设置原型再new对象的情况下让原型链记录正确呢?答案就是重新设置子对象的constructor属性:
function Parent(){}; function Child() { this.constructor = arguments.callee }; Child.prototype = new Parent(); var p = new Parent(); var c = new Child();通过这样的设置,就能达到那张图里所描绘的一条完整的原型链了.
参考的文章: Javascript对象真经 http://w3er.com/blog/2009/03/master-javascript-object-system/#/2009/03/master-javascript-object-system/ 悟透JavaScript https://www.geek-share.com/detail/2414917520.html 《悟透JavaScript》之 甘露模型(新) https://www.geek-share.com/detail/2423567853.html 阅读更多
相关文章推荐
- javascript之对象学习笔记(二)--对象原型,继承
- 【转载】Javascript原型继承-学习笔记
- javascript学习笔记(九)javascript中的原型(prototype)及原型链的继承方式
- JavaScript学习笔记-原型继承
- JavaScript 的原型继承与类式继承学习笔记
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
- javascript学习笔记(九)javascript中的原型(prototype)及原型链的继承方式
- javascript 学习笔记二【原型链模式】
- JavaScript学习笔记(三十二) 经典继承模式二-借用构造方法
- javascript继承学习系列之二:原型链(Prototype Chaining)
- javascript基础学习三:原型继承
- JavaScript学习笔记6 面向对象之继承
- Javascript 设计模式学习笔记(2) - 继承(Inheritance) (上)
- Javascript学习笔记(Object 对象与继承)
- 【09-23】js原型继承学习笔记
- JavaScript原型学习笔记
- javascript 学习笔记(1)对象和原型
- 学习笔记:javascript中的六种继承
- 2016.06.15廖雪峰JS__学习笔记(原型继承)__P9
- javascript 学习笔记之面向对象编程(二):继承&多态