在查阅对象自定义事件及其触发实现的过程中,发现了如下代码:
即:构造函数的原型可以是其他构造方法new出来的对象实例,虽然理解构造函数原型就是一个对象,但通常都是用对象直接量来指定,如:F.prototype ={},这种用法,引起了一些思考:如果原型对象和构造函数定义了完全相同的属性,那么原型方法调研时,作用域是原型对象还是新的对象?为此,做了一下验证:
function ancestor(){ this.name ='default'; this.age = 18; } ancestor.prototype = { printInfo:function(){ console.log( this.name + "," + this.age ); } }; function parent( _name,_age ){ this.name = _name; this.age = _age; } parent.prototype = new ancestor(); var o1 = new parent('tester',20); var o2 = new parent(); console.log( o1 ); console.log( o2 );
打印结果如下:
可见,对象原型和对象自身,都保留了各自的'name'和'age'属性,继续调用对象o1,o2继承自原型的printInfo方法,代码如下:
function ancestor(){ this.name ='default'; this.age = 18; } ancestor.prototype = { printInfo:function(){ console.log( this.name + "," + this.age ); } }; function parent( _name,_age ){ this.name = _name; this.age = _age; } parent.prototype = new ancestor(); var o1 = new parent('tester',20); var o2 = new parent(); console.log('o1-----:'); console.log( o1 ); console.log('o2-----:'); console.log( o2 ); o1.printInfo(); o2.printInfo();
执行结果:
可见:o1,o2在调用继承自原型的方法时,如果自身有了对应的属性定义,则调研的就是对象自身属性,不会上溯至原型对象。
如想切换作用域至原型对象,可以利用方法的call方式来实现:
o1.printInfo.call(Object.getPrototypeOf(o1));
o2.printInfo.call(Object.getPrototypeOf(o2));
结果:
-------------------------补充---------------------------------------------------------------------------------------------------
上面的情况下,当对象没有定义与原型重合的属性时,调用原型方法,会是什么情况?代码如下:
function ancestor(){ this.name ='default'; this.age = 18; } ancestor.prototype = { printInfo:function(){ console.log( this.name + "," + this.age ); } }; function parent(){ } parent.prototype = new ancestor(); var o1 = new parent(); o1.printInfo();
运行结果:
可见,此时最终函数执行的作用域是其原型对象,其实这就是“作用域链”的概念:当对象的方法用到某属性时,会按照对象→原型parent1→原型parent2的链式方式,不断向上追溯查找该属性,直至找到或者为undefined.