js原型淺談理解

以前在學習原型(prototype)的時候,一直對原型的理解不是很清晰,只是知道每一個對象都有一個原型,而後在js中萬物又皆對象。在這裏談一下本身對於js原型的簡單理解吧。數組

原型能夠實現屬性和方法的共享。函數

原型鏈理解:性能

 

假設有一個對象o,其有本身的屬性a和b:學習

{a:1,b:2};this

而後o的原型o.[[prototype]]又有本身的屬性b和c:prototype

{b:3,c:4};對象

最後,o.[[prototype]].[[prototype]]爲null。這就是原型鏈的末尾,即null,根據定義,null沒有[[prototype]]繼承

 

綜上,整個原型鏈以下:ip

{a:1,b:2} ---> {b:3,c:4} ---> null;原型鏈

 

console.log(o.a);  // 1  a爲o的自身屬性

 

console.log(o.b);  // 2  b爲o的自身屬性 可是o.[[prototype]]上面還有個b屬性,可是它不會被訪問到,這種狀況稱之爲屬性遮蔽(property shadowing)

 

console.log(o.c);  // 4  c不是o的自身屬性,那看看o.[[prototype]]上面有沒有,在o.[[prototype]]上找到了c屬性,那麼c的值爲4

 

console.log(o.d);  // undefined 如今o上面找,沒有d屬性;再到o.[[prototype]]上面找,也沒有;最後到o.[[prototype]].[[prototype]]上面找,

o.[[prototype]].[[prototyoe]]爲null,中止尋找,返回undefined。

 

建立一個對象它本身的屬性的方法就是設置這個對象的屬性。惟一例外的獲取和設置的行爲規則就是當有一個 getter或者一個setter 被設置成繼承的屬性的時候。

 

繼承方法:

JavaScript 並無其餘基於類的語言所定義的「方法」。在 JavaScript 裏,任何函數均可以添加到對象上做爲對象的屬性。函數的繼承與其餘的屬性繼承沒有差異,包括上面的「屬性遮蔽」(這種狀況至關於其餘語言的方法重寫)。

 

當繼承的函數被調用時,this 指向的是當前繼承的對象,而不是繼承的函數所在的原型對象。

var o = {

  n:1,

  m:function(){

    return this.n + 1;

  }

};

console.log(o.m()); // 2    當調用m方法時,this指向o;

var p = Object.create(o);

p.n = 10;

console.log(p.m()); // 11  調用m方法時,this指向當前調用它的p;

Object.create()建立一個新對象,新對象的原型就是調用時傳入的第一個參數;

因此上面原型鏈爲:

p ---> o ---> Obejct.prototype ---> null;

o繼承了Object上面全部的屬性和方法;因此對象所具備的屬性和方法,o均可以使用;

對象具備hasOwnProperty()屬性; 注意:hasOwnProperty() 判斷的只是本身是否具備該屬性或者方法 繼承過來的屬性和方法不算自身的;

hasOwnProperty 是 JavaScript 中惟一一個只涉及對象自身屬性而不會遍歷原型鏈的方法。

  console.log(o.hasOwnProperty('m'));   // true;  o對象有本身的m方法

  console.log(p.hasOwnProperty('m'));  // false;   p對象沒有本身的m方法 它是繼承自o的

 

var arr = [1,'str',true,o];

數組都繼承自Array.prototype(indexOf,forEach等方法都是從它繼承而來);

 原型鏈以下:

arr ---> Array.prototype ---> Object.prototype ---> null;

 

function a(b){

  return b;

}

函數都繼承自Function.prototype(call,bind等方法都是繼承而來);

原型鏈以下:

a ---> Function.prototype ---> Object.prototype ---> null;

 

使用構造器建立函數:

在js中,構造器其實就是一個簡答的函數,當使用new操做符來操做這個函數時,它就能夠被稱爲構造函數(構造方法);

function Person(){

  this.eyes = [];

  this.hands = [];

}

Person.prototype.addEyes= function(e){

  this.eyes.push(e);

}

var p  = new Person();

p是生成的對象,它自身有屬性'eyes' 和 'hands',在p被實例化的時候,它的原型指向Person.prototype;

 

 

在用原型繼承編寫複雜代碼前理解原型繼承模型十分重要。同時,還要清楚代碼中原型鏈的長度,並在必要時結束原型鏈,以免可能存在的性能問題。此外,除非爲了兼容新 JavaScript 特性,不然,永遠不要擴展原生的對象原型。

相關文章
相關標籤/搜索