js _proto__ 和prototype

object的_proto_ 和 函數(shù)的prototype
prototype是函數(shù)的一個屬性,這個屬性是一個指針,用來指向一個對象;_proto是一個對象擁有的內(nèi)置隱式原型屬性,js內(nèi)部通過_proto來尋找原型鏈屬性,假如對象內(nèi)部不存在某個屬性,就會從_proto中去尋找,_proto也會有自己的_proto_,直到找到未知,這就是我們所說的原型鏈的概念。

  • _proto_ 和 prototype
function Base () {
  this.name = 'Base';
}
var instance = new Base();

// console.log()
instance.__proto__ === Base // false
instance.__proto__ === Base.prototype  // true
instance.__proto__.constructor  === Base.prototype  // false
instance.__proto__.constructor  === Base // true

Base是構(gòu)造函數(shù),如果進行new Base()操作,那么首先會進行初始化一個空{(diào)},然后將{}的 proto 即隱式原型指向Base的prototype,然后執(zhí)行了 Base.call({}) 將this作用域交予{},然后就完成了實例化。
所以instance的proto 是等于Base的prototype的,那么Base.prototype.constructor 自然是指向本身了。

function Base () {
  this.name = 'Base';
}
var instance = new Base();
instance.__proto__.constructor === Base // true
instance.__proto__.constructor === Base.prototype.constructor  // true
instance.__proto__ === Base.prototype // true

由上述代碼,我們應該已經(jīng)理解了 _proto_和prototype的區(qū)別了
如果改變一下代碼:

function Base () {
  this.name = 'Base';
}
Base.prototype.play = () => { console.log('play') };
var instance = new Base();
// console.log()
instance

打印的instance是存在下列屬性,一個是顯示的name,一個是隱式的proto,展開proto就是Base的prototype,即隱式的構(gòu)造函數(shù)和proto,還有一個顯式的play函數(shù);

  • extends
    es6
class Base {
  constructor () {
    this.name = 'Base';
  }
  play () {
     console.log('play');
  }
};
class A extends Base {
  constructor () {
    super();
    this.age = 15;
  }
}
const instanceA = new A();

// console.log()
instanceA.name // Base
instanceA.age  // 15

如何實現(xiàn)的呢?
由上面的知識,我們可以知道 當執(zhí)行一個new() 操作之后,新變量的proto 指向構(gòu)造函數(shù)的prototype,那么我們大膽地打印一下instanceA.proto和A.prototype看一下結(jié)果。

class Base {
  constructor () {
    this.name = 'Base';
  }
  play () {
     console.log('play');
  }
};
class A extends Base {
  constructor () {
    super();
    this.age = 15;
  }
}
const instanceA = new A();
// console.log()
instanceA.__proto__    //  打印結(jié)果是一個擁有constructor  和__proto__的object,即A的實例化結(jié)果
A.prototype   // 打印結(jié)果是一個擁有constructor  和__proto__的object,即 ?的實例化結(jié)果
instanceA.__proto__ === A.prototype  // true 那么上面的?號應該是Base無疑了

由此可以看出es6 class 的語法糖是如何構(gòu)造的了。
如果我們使用一個class繼承另外一個class,就是將本身的prototype指向父class的實例化了
看看es5的代碼:

function Base () { this.name = 'Base' };
function A () { this.age = 15 };
cosnt instanseA = new A();

那么如何才能讓A繼承到Base呢?

function Base () { this.name = 'Base' };
Base.prototype.play = () => {  console.log('play') };
function A () { this.age = 15 };
A.prototype = new Base();
cosnt instanseA = new A();
// console.log()
instanseA.name // 'Base'
instanseA.age // 15 
instanseA.play // function

原理剖析:A的實例化是instanseA ,當讀取instanseA上面的屬性name時,發(fā)現(xiàn)不存在,只能從proto上面尋找,instanseA 的proto指向的是A的prototype,A的prototype下面有兩個屬性,一個是constructor,一個是proto,發(fā)現(xiàn)A上面也沒有;然后我們寫了這么一行代碼,是A.prototype = new Base();也就是說通過instanseA.proto 找到了A的prototype,就找到了Base的實例化,Base的實例化應該是有兩個屬性,一個是name,一個是proto,然而發(fā)現(xiàn)只能讀取到name,并沒有play函數(shù),然后又從Base的proto上面查找,我們寫了Base.prototype.play是一個函數(shù),所以在proto 上面就找到了play函數(shù)。
一個函數(shù)的prototype上面掛在的函數(shù)可以在實例化的proto_找到。
以上原理總結(jié)一句話就是:
父類屬性放構(gòu)造函數(shù), 父類方法放原型鏈, 子類prototype指向父實例, 子類構(gòu)造函數(shù)調(diào)用父類構(gòu)造函數(shù), 子類構(gòu)造函數(shù)指回自己)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容