首先呢,prototype是对象里的一个内置属性,而且呢,这个属性是对于其余对象的一个引用。因此呢,思考下面的例子:函数
var obj = { a: 2 } var myObj = Object.create(obj); console.log(myObj.a); // 2 console.log(myObj === obj); // false console.log(Object.getPrototypeOf(myObj) === obj); // true Object.getPrototypeOf(myObj).a = 4 console.log(obj.a); // 4
这里能够看到,实际上Object.create()是新建了一个对象,而且这个对象的prototype是obj的一个引用,因此呢,若是我们直接修改prototype里面的值,原对象也就跟着变了。编码
很简单吧,那么若是执行以下代码的话,会发生什么呢?prototype
myObj.a = 10;
是否是认为,还跟上面那个同样的,obj.a也变成10了呢?实际上不是的,他的运行机制要比我们想的稍微复杂一点点。code
实际上要分三种状况来看:对象
若是在prototype链上存在这个属性,而且没有标记为只读,那么就会在本对象上新建一个新的同名属性。原型链
若是在prototype链上存在这个属性,而且标记为只读,那么将没法修改已有属性或在本对象上新建一个同名属性,若是是严格模式的话,还会报错。get
若是在prototype链上只是存在此setter,那么必定会调用此setter,并不会添加属性到对象上,更不会从新定义这个setter原型
很枯燥是吧,来看例子,对照着上面的状况,好好的理解一下:it
var obj = { a: 2, set c(num) { console.log('exec it'); } } var myObj = Object.create(obj); myObj.a = 10; console.log(obj.a); // 2 console.log(myObj.a); // 10 Object.defineProperty(obj, 'b', { value: 3, writable: false }) myObj.b = 10; console.log(myObj.b); // 3 myObj.c = 20; // "exec it" console.log(myObj.c); // undefined
假如上面的已经理解了,那么能够思考下下面的运行结果:io
var obj = { a: 2 } var myObj = Object.create(obj); console.log(++myObj.a); // 3 console.log(obj.a); // 2
这个在我们实际的编码中时有发生,看代码是想把a改为3,可是因为上面第一种状况的影响,其实是新建了一个同名属性3,而且赋值给了myObj。
上面咱们谈论的都是普通对象的prototype的一些特性,接下来,我们就要讲关于new关键字相关的一些知识点了,思考下面的例子
function Foo() {} var a = new Foo(); console.log(Object.getPrototypeOf(a) === Foo.prototype); // true var b = new Foo(); Object.getPrototypeOf(b).saySomething = function () { console.log('say something'); } a.saySomething(); // "say something"
很明显,在new的过程当中呢,生成了一个新对象,而且把Foo.prototype引用到了新对象的prototype。那么由于是引用,因此经过b改变其原型上的prototype的值,Foo.prototype里也会跟着改变。
那么new的过程,是否是必定引用的是函数的prototype呢?也不必定,好比说下面的例子。
function Foo() { return { a: 3 } } var a = new Foo(); console.log(Object.getPrototypeOf(a) === Foo.prototype); // false console.log(Object.getPrototypeOf(a) === Object.prototype); // true console.log(a.a); // 3
在这个例子中,因为new的时候,返回的是一个对象,因此最后实际上a最终引用的是Foo最后返回的那个小对象,因此其prototype就是Object.prototype,而不是Foo.prototype
甚至说,Foo.prototype也是能够被改变的,不过在这时候,new出来的对象,其prototype就是被改过的那个对象。
var protoObj = { b: 10 } function Foo() {} Foo.prototype = protoObj; var a = new Foo(); console.log(Object.getPrototypeOf(a) === Foo.prototype); // true console.log(Object.getPrototypeOf(a) === protoObj); // true console.log(a.b); // 10
你看,若是prototypeObj修改了默认的Foo.prototype,因此最后,实际上造成了这么一个引用链:a.prototype => foo.prototype => protoObj=>Object.prototype。
因此说结论吧,在new的时候,实际上执行会包含这么几步,
若是有return而且返回的是一个对象的话,则直接返回return后的那个对象。
反之,则新建一个对象。
而且吧函数的prototype引用到新建对象的prototype中。
因此说,原型,能够理解为我原本对象有一个prototype,引用着其余的对象,当我这个对象的prototype引用了另外一个对象的prototype,通常状况会到Object.prototype为止,这样就组成了一个原型链,原型链也就是互相引用的引用链。而这个引用链是能够根据本身的需求去改。
好了,简短的一小节就完事了,若是有不明白的,或者有疏漏的地方,或者有什么地方想和我讨论的,能够留言给我哦