JavaScript對象有一個指向一個原型對象的鏈,當試圖訪問一個對象的屬性的時候,他不單單會在該對象上面搜尋,還會搜尋該對象的原型,以及對象的原型的原型,依次層層搜索,直到找到名字匹配的屬性或者到達原型鏈的末端javascript
// 讓咱們假設咱們有一個對象 o, 其有本身的屬性 a 和 b: // {a: 1, b: 2} // o 的 [[Prototype]] 有屬性 b 和 c: // {b: 3, c: 4} // 最後, o.[[Prototype]].[[Prototype]] 是 null. // 這就是原型鏈的末尾,即 null, // 根據定義,null 沒有[[Prototype]]. // 綜上,整個原型鏈以下: // {a:1, b:2} ---> {b:3, c:4} ---> null console.log(o.a); // 1 // a是o的自身屬性嗎?是的,該屬性的值爲1 console.log(o.b); // 2 // b是o的自身屬性嗎?是的,該屬性的值爲2 // 原型上也有一個'b'屬性,可是它不會被訪問到.這種狀況稱爲"屬性遮蔽 (property shadowing)" console.log(o.c); // 4 // c是o的自身屬性嗎?不是,那看看原型上有沒有 // c是o.[[Prototype]]的屬性嗎?是的,該屬性的值爲4 console.log(o.d); // undefined // d是o的自身屬性嗎?不是,那看看原型上有沒有 // d是o.[[Prototype]]的屬性嗎?不是,那看看它的原型上有沒有 // o.[[Prototype]].[[Prototype]] 爲 null,中止搜索 // 沒有d屬性,返回undefined
當繼承的函數被調用時,this
指向的是當前繼承的對象,而不是繼承的函數所在的原型對象。
java
var o = { a: 2, m: function(){ return this.a + 1; } }; console.log(o.m()); // 3 // 當調用 o.m 時,'this'指向了o. var p = Object.create(o); // p是一個繼承自 o 的對象 p.a = 4; // 建立 p 的自身屬性 a console.log(p.m()); // 5 // 調用 p.m 時, 'this'指向 p. // 又由於 p 繼承 o 的 m 函數 // 此時的'this.a' 即 p.a,即 p 的自身屬性 'a'
var o = {a: 1}; // o 這個對象繼承了Object.prototype上面的全部屬性 // o 自身沒有名爲 hasOwnProperty 的屬性 // hasOwnProperty 是 Object.prototype 的屬性 // 所以 o 繼承了 Object.prototype 的 hasOwnProperty // Object.prototype 的原型爲 null // 原型鏈以下: // o ---> Object.prototype ---> null var a = ["yo", "whadup", "?"]; // 數組都繼承於 Array.prototype // (Array.prototype 中包含 indexOf, forEach等方法) // 原型鏈以下: // a ---> Array.prototype ---> Object.prototype ---> null function f(){ return 2; } // 函數都繼承於Function.prototype // (Function.prototype 中包含 call, bind等方法) // 原型鏈以下: // f ---> Function.prototype ---> Object.prototype ---> null
在 JavaScript 中,構造器其實就是一個普通的函數。當使用 new 操做符 來做用這個函數時,它就能夠被稱爲構造方法(構造函數)。數組
function Graph() { this.vertices = []; this.edges = []; } Graph.prototype = { addVertex: function(v){ this.vertices.push(v); } }; var g = new Graph(); // g是生成的對象,他的自身屬性有'vertices'和'edges'. // 在g被實例化時,g.[[Prototype]]指向了Graph.prototype.
Object.create
建立的對象ECMAScript 5 中引入了一個新方法:Object.create()
。能夠調用這個方法來建立一個新對象。新對象的原型就是調用 create
方法時傳入的第一個參數:ide
var a = {a: 1}; // a ---> Object.prototype ---> null var b = Object.create(a); // b ---> a ---> Object.prototype ---> null console.log(b.a); // 1 (繼承而來) var c = Object.create(b); // c ---> b ---> a ---> Object.prototype ---> null var d = Object.create(null); // d ---> null console.log(d.hasOwnProperty); // undefined, 由於d沒有繼承Object.prototype
class
關鍵字建立的對象ECMAScript6 引入了一套新的關鍵字用來實現 class。使用基於類語言的開發人員會對這些結構感到熟悉,但它們是不一樣的。JavaScript 仍然基於原型。這些新的關鍵字包括 class
, constructor
,static
,extends
和 super
。函數
"use strict"; class Polygon { constructor(height, width) { this.height = height; this.width = width; console.log(height) //2 } } class Square extends Polygon { constructor(sideLength) { super(sideLength, sideLength); } get area() { return this.height * this.width; } set sideLength(newLength) { this.height = newLength; this.width = newLength; } } var square = new Square(2);
function Graph() { this.vertices = []; this.edges = []; } Graph.prototype = { addVertex: function(v){ this.vertices.push(v); } }; var g = new Graph(); console.log(g.hasOwnProperty('vertices')); // true console.log(g.hasOwnProperty('nope')); // false console.log(g.hasOwnProperty('addVertex')); // false console.log(g.__proto__.hasOwnProperty('addVertex')); // true
hasOwnProperty
是 JavaScript 中惟一處理屬性而且不會遍歷原型鏈的方法。性能
所以,當你執行:this
var o = new Foo();
JavaScript 實際上執行的是(或者大體這樣):prototype
var o = new Object(); o._proto_ = Foo.prototype; Foo.call(0)
o.someProp;
它檢查
o
是否具備someProp
屬性。code若是沒有,它會查找
Object.getPrototypeOf(o).someProp
,對象若是仍舊沒有,它會繼續查找
Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp
。
ps:
Object.getPrototypeOf()
方法返回指定對象的原型(內部[[Prototype]]
屬性的值)。
var proto = {}; var obj = Object.create(proto); var a= Object.getPrototypeOf(obj) console.log(a); {}
若是以爲還不錯,請訪問MDN