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内里的值,原对象也就随着变了。

很简单吧,那末如果实行以下代码的话,会发作什么呢?

myObj.a = 10;

是否是以为,还跟上面谁人一样的,obj.a也变成10了呢?现实上不是的,他的运转机制要比我们想的轻微庞杂一点点。

现实上要分三种状况来看:

如果在prototype链上存在这个属性,而且没有标记为只读,那末就会在本对象上新建一个新的同名属性。

如果在prototype链上存在这个属性,而且标记为只读,那末将没法修正已有属性或在本对象上新建一个同名属性,如果是严厉形式的话,还会报错。

如果在prototype链上只是存在此setter,那末肯定会挪用此setter,并不会增加属性到对象上,更不会从新定义这个setter

很死板是吧,来看例子,对比着上面的状况,好好的明白一下:

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

如果上面的已明白了,那末能够思索下下面的运转效果:

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/

    原文作者:小辞
    原文地址: https://segmentfault.com/a/1190000017860282
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞