Javascript基础之-原型(prototype)

首先呢,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为止,这样就组成了一个原型链,原型链也就是互相引用的引用链。而这个引用链是能够根据本身的需求去改。

好了,简短的一小节就完事了,若是有不明白的,或者有疏漏的地方,或者有什么地方想和我讨论的,能够留言给我哦

本文转载自http://www.lht.ren/article/8/

相关文章
相关标签/搜索