昨天阿里实习的第一次电面,也是我人生中的第一次电面,问了很多问题。结果还行吧,算是进入了下一轮。虽然不知道姓名,但还是要感谢面我的那个前辈。好吧,言归正传,为什么要写这篇关于原型的博文呢?因为电面时被问到了。当时有点紧张,感觉回答的很不理想,也许是自己还没有牢固的掌握吧!所以今天就写一写我对原型的理解,顺便理一下自己的思路。
首先,JS没有类继承机制,它是靠原型机制实现继承的,两种方式孰优孰劣,在此不做评判(知识量不足╮(╯▽╰)╭)
先上代码解释这一机制:
var people = { name: 'xiaoliu' };
对于JS中所有对象,都有一个内部属性(供解释器使用)_proto_,这个属性指向新建对象的原型,people对象字面量的原型是什么呢,它是Object.prototype。
如图:
当我们想执行toString()方法时,JS解释器做了什么呢?首先它会到peope对象里去找,即去找people里的自有属性,当找到了就去调用该方法,没找到,就到它_proto_所引用对象里去找,找到了,他就执行原型里的这个方法(子类属性覆盖父类属性)。所以我们说people对象继承了object.prototype里的方法,但是我更推荐大家这么说Object.prototype是people对象的原型。
下面咱们来做这么一件事:
people.toString = functino(){};
JS解释器会做什么呢,他还会到原型上找到toString属性然后赋值么。当然不行,这样做的话,所有继承了Object.prototype的对象的toString属性都会改变。因此赋值时JS解释器就直接看people对象里的自有属性有没有,如果有,改。如果没,就新建一个属性赋值。
上代码证明:
var people = { name: 'xiaoliu' }; console.log(people.hasOwnProperty('toString'));/*赋值前 false*/ people.toString = function(){}; console.log(people.hasOwnProperty('toString'));/*赋值后 true*/
这样查找属性和属性赋值都没问题了,原型继承就这么实现了。
不过JS是不允许我们随意修改对象的原型链的,ES5中Object对象上有个getPrototypeOf()方法可以查看原型,但是无法修改。
下面再说说JS怎么初始化新建对象的原型的:
首先, 是对象字面量,上面已经说了,原型初始化成Object.prototype对象。
其次, 是利用对象模板(函数),使用new 运算符创建的对象,它会初始化成为该函数的prototype属性所指向的对象。
代码实例:
function People(){ this.name = 'xiaoliu'; }/*对象模板*/ People.prototype = {
constructor: People,/*原来People.prototype指向的对象中默认的唯一不可枚举属性,现在修改了prototype的引用,所以最好再恢复一下*/
toString: function(){return this.name}
};/*修改原型*/ var people = new People();/*创建对象*/ people.toString();/*执行继承方法*/
最后,是通过ES5提供的Object.create()方法
代码实例:
var people = {name: 'xiaoliu'}; var a = Object.create(people);/*创建一个新对象,并把原型_proto_初始化为people对象*/ a.name;/*返回原型链上的name属性*/
好吧,先到此为止吧,以后有机会再谈谈this。
如有错误,欢迎指正^_^