【翻譯】javascript原型繼承到底是如何?的

來源:互聯網
上載者:User

寫文章之前先講個笑話,活躍一下氣氛——

校長:“先生,我有一個好訊息,一個壞訊息,都是關於您兒子的。” 家長:“校長,先說壞訊息吧!”

校長:“壞訊息是,您的兒子的動作十分女性化。” 家長:“那好訊息呢?” 校長:“好訊息是他現在是本校校花。”

 

言歸正傳,先放原文地址:

http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html
這是我第一次翻譯別人的文章,不到之處,敬請諒解。
全文:
javascript——原型繼承到底是如何?的

在網上,我們到處都看到javascript是基於原型的繼承。儘管如此,javascript預設僅僅只是通過new操作符提供一種特殊形式的原型繼承
因此,許多言論和解釋都是難以理解的。本文就是剖析原型繼承的實質以及如何使用原型繼承。

原型繼承定義
當我們遇到原型繼承時,我們通常會看到如下的一段解釋:
當需要讀取一個對象的屬性時,javascript會沿著原型鏈向上尋找直到發現吻合的屬性為止。
在多數的javascript實現中,__proto__用來表示原型鏈的下一個對象,
在接下來的內容中,我們會發現__proto__與prototype的不同之處。
Note:__proto__是非標準的 ,因此不應該出現在你的正式代碼中,本文使用這個屬性,只為明理,而非實用。

下面的代碼揭示了javascript引擎是如何檢索一個屬性的
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop))
return obj[prop]

else if (obj.__proto__ !== null)
return getProperty(obj.__proto__, prop)

else
return undefined
}

我們舉一個通俗的例子:二位座標點。一個點有x、y兩個座標和一個print方法。
遵循上面的原型繼承定義,我們來產生一個具有3個屬性(x、y、print)的對象,為了建立一個新的點,用__proto__來建立一個點對象。
var Point = {
x: 0,
y: 0,
print: function () { console.log(this.x, this.y); }
};

var p = {x: 10, y: 20, __proto__: Point};
p.print(); // 10 20

javascript怪異的原型繼承
讓人迷惑的是,每一個引用上面的定義來教授javascript原型繼承的人都沒有給出類似上面的代碼,
取而代之的是類似下面的代碼:

function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
print: function () { console.log(this.x, this.y); }
};

var p = new Point(10, 20);
p.print(); // 10 20

這與我們上面的代碼完全不一樣,Point現在是一個函數,我們使用prototype屬性,使用new操作符,真是苦逼啊。

new操作符是怎麼工作的?
Brendan Eich(JavaScript的發明人)想讓javascript看起來與一些傳統的物件導向語言(比如Java,C++)跟接近,在哪些傳統語言中,通過new操作符來建立一個類的執行個體,因此,他也跟風實現了new操作符。
C++有建構函式的概念,用來初始化一個執行個體屬性。因此,new操作符必須用在一個函數上。
對象的方法需要有地方存放,鑒於我們在使用原型式語言,我們就把他放在函數的prototype屬性裡面

new操作符就像含有一個F函數,以及參數new F(arguments),幾個步驟如下:
1、建立一個類的執行個體,得到的是一個__proto__指向F。protoype的Null 物件。
2、初始化前面得到的Null 物件,也就是執行個體。在這一步,F函數被調用,並且將參數傳遞進來,將this指向第一步的執行個體。
3、返回這個執行個體

可能說的不好理解,我們用代碼方式來實現他的的步驟:
function New (f) {
/*1*/ var n = { '__proto__': f.prototype };
return function () {
/*2*/ f.apply(n, arguments);
/*3*/ return n;
};
}

下面是示範其工作原理的一個小例子:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
print: function () { console.log(this.x, this.y); }
};

var p1 = new Point(10, 20);
p1.print(); // 10 20
console.log(p1 instanceof Point); // true

var p2 = New (Point)(10, 20);
p2.print(); // 10 20
console.log(p2 instanceof Point); // true

javacsript中真正的原型繼承

javascript標準僅僅給出類new操作符。儘管如此,Douglas Crockford找到了一個方法利用new來實現真正的原型繼承。他寫出了如下的 Object.create函數:

Object.create = function (parent) {
function F() {}
F.prototype = parent;
return new F();
};

這樣看起來很怪異,但是卻是很簡單。這個函數僅僅建立了新對象,並且他的原型可以指向任何你想要指向的位置,如果我們可以隨意使用__proto__,我們也可以這麼寫:
Object.create = function (parent) {
return { '__proto__': parent };
};

下面用真正的原型繼承來改寫我們上面的座標點例子:
var Point = {
x: 0,
y: 0,
print: function () { console.log(this.x, this.y); }
};

var p = Object.create(Point);
p.x = 10;
p.y = 20;
p.print(); // 10 20

結論:
我們討論了什麼是原型繼承,以及javascript是怎樣通過一種特別的方式來實現。
儘管如此,真正的原型繼承(Object.create 和 __proto__)使用起來還是有一些缺點的:
1、不是標準方法:__proto__是不標準甚至是已淘汰的,原生的Object.create方法與Douglas Crockford的實現並不是完全等價的。
2、不夠最佳化:Object.create (不管是原生的還是模仿的)都不如new操作符最佳化,速度差距可能達到10倍。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.