由一段代码印发的思考
function A(){}
var a = new A();
A.prototype = {x:3};
console.log(a.x);
想一下这段代码会输出什么,会输出3么,如果你的答案是3,那么恭喜你,下面的东西也是你需要的。
首先,正确的答案是undefined,不相信可以在控制台输出一下,结果一定是undefined,也就是说,a中并不存在一个 x
属性,如果我们将代码改成这样,再看看结果是什么样子的:
function A(){}
var a = new A();
Object.prototype.x=3;
console.log(a.x);
这次再试一下,你会发现输出了3,是否找到问题了呢?
当我们在创建一个构造函数,也就是function A
的时候,虽然没有规定他的prototype
属性,但是JavaScript中明确指出,没一个JavaScript对象都和另一个对象关联,就是原型,换句话说,每一个JavaScript对象都有原型,那就证明A
也是有原型的,而且原型值指向Object对象。
所以,当我们实例化一个A
的对象a
的时候,a
会继承A
的属性,而A
的属性中并不存在自有属性,所以A
的属性实际上就是继承自Object,因此,a
的原型是指向Object的。
第一段代码,a
的原型指向Object,这时我们设置A的prototype,也就是改变了A的原型,但是之前实例化的a
的原型并没有继承A
的属性,而是直接指向了Object,所以并不会受到影响。而Object的属性中也没有一个属性是x
,JS中使用一个不存在的属性会返回一个undefined。
第二段代码,我们直接给Object的prototype添加一个x的属性,此时在a
中就可以拿到x
属性的值了。
如果我们将第二段代码中的
Object.prototype.x=3;
替换成
Object.x=3;
你会发现还是会输出同样的结果,其实js的继承,只有在查询属性的时候才会体现出来,查找一个对象的属性的时候,先会在对象的自有属性中进行查找,如果有就直接返回,如果没有会在对象的原型中查找,如果原型中也没有找到,就在原型的原型中查找,,,,这样传说中的原型链也就形成了。
有些时候我们在使用new
方法创建对象的时候,比如new Date()
这样的方式创建的对象,他的prototype指向的是DDate
对象,而Date
的prototype也继承自Object。