1. 程式人生 > 其它 >關於JavaScript原型鏈

關於JavaScript原型鏈

技術標籤:JavaScript學習關於面試

關於JavaScript原型鏈

建立物件的方法

在瞭解原型鏈之前,先了解以下三種建立物件的幾種方式:

    //第一種:字面量
    var o1={name:'o1'}
    var o2=new Object({name:'o2'})

    //第二種:建構函式
    var M=function(name){this.name=name;}
    var o3=new M('o3')

    //第三種:Object.create
    var s={name:'s'}
    var o4=Object.create(s)

列印結果:

o1:{ name: ‘o1’ }
o2:{ name: ‘o2’ }
o3:M { name: ‘o3’ }
o4:{}

型及原型鏈

先來一張圖
img

什麼是例項?原型物件?建構函式?

var M=function(name){this.name=name;}
var o3=new M('o3')

在這段程式碼裡:

  • 例項就是物件,o3即為例項,M為建構函式
  • 例項通過new一個建構函式生成
  • 從上圖可知,例項的__proto__指向原型物件,例項的建構函式的prototype也指向原型物件,原型物件的construor指向的是建構函式
  • M的prototype指向原型物件,o3的 __proto__也指向同一個原型物件,因為o3是通過M new出來的,即( o3.__proto__===M.prototype) 為true
  • 原型物件裡的 constructor 屬性就是建構函式
  • M.prototype.constructor===M 為true,即M的原型物件的建構函式就是M本身

那什麼是原型鏈?

每個例項物件 (object )都有一個私有屬性(稱之為 __proto__ )指向它的建構函式的原型物件(prototype )。該原型物件也有一個自己的原型物件( __proto__ ) ,層層向上,直到一個物件的原型物件為 null,形成一條原型鏈。根據定義,null 沒有原型,並作為這個原型鏈中的最後一個環節。

原型物件和例項之間有什麼作用呢?

當通過一個建構函式創建出來的多個例項都要新增一個方法時,若給每個例項都去新增該方法並不是一個明智的選擇,這時原型的作用就明顯了。

在例項的原型上新增此方法,那麼這個原型的所有例項就都有了這個方法。

接著上面的例子演示:

    var M = function (name) { this.name = name; }
    var o3 = new M('o3')
    var o5 = new M()
    M.prototype.say=function(){
      console.log('hello')
    }
    // o3.__proto__.say=function(){
    //   console.log('hello')
    // }
    o3.say()
    o5.say()

通過建構函式的prototype屬性和例項的__proto__屬性新增方法都可

列印結果:

hello
hello

【補充】

  • 只有函式有prototype,物件是沒有的
  • 函式也是有__proto__的,因為函式也是物件
  • 函式的__proto__指向Function.prototype
  • 即 普通函式是Function這個建構函式的一個例項

instanceof 原理

img
instanceof判斷的是 例項物件的__proto__和生成該例項的建構函式的prototype是否引用自同一個地址,即判斷constructor.prototype是否存在於例項物件的原型鏈上。

是則返回true,不是返回false。

那麼怎麼判斷例項是由哪個建構函式生成的呢?這時就要用到constructor了。

obj.__proto__.constructor 例項的原型的建構函式

o3.__proto__.constructor===M   //true
o3.__proto__,constructor===Object  //false

new 運算子

new 關鍵字的操作?

1.建立一個空的簡單JavaScript物件(即{})
2.連結該物件(設定該物件的constructor)到另一個物件
3.將步驟1新建立的物件作為this的上下文
4.若該函式沒有返回物件,則返回this


建立一個使用者自定義物件需要兩步:

1.編寫函式實現定義物件型別
2.通過new建立物件例項


當執行程式碼 new Foo(…) 時,會發生以下事情:

1.一個繼承自Foo.prototype的新物件被建立

2.使用指定的引數呼叫建構函式Foo,並將this繫結到新建立的物件。(new Foo等同於new Foo(),也就是沒有指定引數列表,Foo不帶任何引數呼叫的情況)

3.由建構函式返回的物件就是new表示式的結果(若建構函式沒有顯式返回一個物件,則使用步驟1建立的物件)

如果你沒有使用 new 運算子, 建構函式會像其他的常規函式一樣被呼叫, 並不會建立一個物件。在這種情況下, this 的指向也是不一樣的。

基於new的工作原理,手動實現一個new運算子:

 var new1=function(func){
      var o=Object.create(func.prototype);//建立物件
      var k=func.call(o);//改變this指向,結果賦給k
      if(typeof k ==='object')return k;//k是物件,返回k
      else return o;//若k不為物件,則返回建構函式的執行結果
    }

Object.create()

使用該方法建立一個新物件,使用現有的物件來提供新建立的物件的__proto __。

參考文章