天天看點

函數進階① -- (函數的prototype、原型、原型鍊)

文章目錄

  • ​​函數的prototype​​
  • ​​顯示原型與隐式原型​​
  • ​​原型鍊​​
  • ​​構造函數/原型/執行個體對象的關系​​

函數的prototype

  1. 函數的prototype屬性
  • 每個函數都有一個prototype屬性, 它預設指向一個Object空對象(即稱為: 原型對象)
  • 原型對象中有一個屬性constructor, 它指向函數對象
  • 函數進階① -- (函數的prototype、原型、原型鍊)
也就是說函數與函數的原型對象有一個互相引用的關系
  1. 給原型對象添加屬性(一般都是方法)
  • 作用: 函數的所有執行個體對象自動擁有原型中的屬性(方法)

證明:

<script type="text/javascript">

  // 每個函數都有一個prototype屬性, 它預設指向一個Object空對象(即稱為: 原型對象)
  console.log(Date.prototype, typeof Date.prototype)
  function Fun () {//alt + shift +r(重命名rename)

  }
  console.log(Fun.prototype)  // 預設指向一個Object空對象(沒有我們的屬性)

  // 原型對象中有一個屬性constructor, 它指向函數對象
  console.log(Date.prototype.constructor===Date)
  console.log(Fun.prototype.constructor===Fun)

  //給原型對象添加屬性(一般是方法) ===>執行個體對象可以通路
  Fun.prototype.test = function () {
    console.log('test()')
  }
  var fun = new Fun()
  fun.test()
</script>      

顯示原型與隐式原型

  1. 每個函數function都有一個prototype,即顯式原型(屬性)
  2. 每個執行個體對象都有一個__proto__,可稱為隐式原型(屬性)
  3. 對象的隐式原型的值為其對應構造函數的顯式原型的值
  4. 記憶體結構(圖)
  5. 總結:
  • 函數的prototype屬性: 在定義函數時自動添加的, 預設值是一個空Object對象
  • 對象的__proto__屬性: 建立對象時自動添加的, 預設值為構造函數的prototype屬性值
  • 程式員能直接操作顯式原型, 但不能直接操作隐式原型(ES6之前)

例如:

函數進階① -- (函數的prototype、原型、原型鍊)
<script type="text/javascript">
  //定義構造函數
  function Fn() {   // 内部語句: this.prototype = {}

  }
  // 1. 每個函數function都有一個prototype,即顯式原型屬性, 預設指向一個空的Object對象
  console.log(Fn.prototype)
  // 2. 每個執行個體對象都有一個__proto__,可稱為隐式原型
  //建立執行個體對象
  var fn = new Fn()  // 内部語句: this.__proto__ = Fn.prototype
  console.log(fn.__proto__)
  // 3. 對象的隐式原型的值為其對應構造函數的顯式原型的值
  console.log(Fn.prototype===fn.__proto__) // true
  //給原型添加方法
  Fn.prototype.test = function () {
    console.log('test()')
  }
  //通過執行個體調用原型的方法
  fn.test()
</script>      

原型鍊

原型鍊

  • 通路一個對象的屬性時,
  • 先在自身屬性中查找,找到傳回
  • 如果沒有, 再沿着__proto__這條鍊向上查找, 找到傳回
  • 如果最終沒找到, 傳回undefined
  • 别名:隐式原型鍊
  • 作用: 查找對象的屬性(方法)
函數進階① -- (函數的prototype、原型、原型鍊)

注意:

/*
  1. 函數的顯示原型指向的對象預設是空Object執行個體對象(但Object不滿足)
   */
  console.log(Fn.prototype instanceof Object) // true
  console.log(Object.prototype instanceof Object) // false
  console.log(Function.prototype instanceof Object) // true
  /*
  2. 所有函數都是Function的執行個體(包含Function)
  */
  console.log(Function.__proto__===Function.prototype)
  /*
  3. Object的原型對象是原型鍊盡頭
   */
  console.log(Object.prototype.__proto__) // null      

構造函數/原型/執行個體對象的關系

例一:

var o1 = new Object();
var o2 = {};      
函數進階① -- (函數的prototype、原型、原型鍊)

例二:

function Foo(){  }      
函數進階① -- (函數的prototype、原型、原型鍊)

這張圖有幾個注意點:

  • Foo的構造函數的__proto__指向Function的原型對象,因為執行個體對象的__proto__永遠指向構造函數的prototype。
  • Function自己也是Function的執行個體對象,既然是對象那麼就有__proto__屬性,根據執行個體對象的__proto__永遠指向構造函數的prototype,我們可以知道Function的__proto__指向Function的原型對象。
  • Object的構造函數是Function的執行個體對象,同樣也根據執行個體對象的__proto__永遠指向構造函數的prototype,是以Object的構造函數的__proto__指向Function的原型對象。

繼續閱讀