亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深入理解 JavaScript 原型繼承

UCloud / 1593人閱讀

摘要:下面輪到我們的主角原型繼承登場了,它從另一個(gè)角度解決了重用的問題。原型繼承的原理原型對象中的由兩部分組成,普通屬性的集合,和原型屬性。原型繼承的實(shí)現(xiàn)在上面的例子中,通過直接修改了屬性值,實(shí)現(xiàn)了原型繼承。使用原型繼承,同樣可以達(dá)到重用的目的。

繼承的本質(zhì):重用

在探討 JavaScript 的原型繼承之前,先不妨想想為什么要繼承?

考慮一個(gè)場景,如果我們有兩個(gè)對象,它們一部分屬性相同,另一部屬性不同。通常一個(gè)好的設(shè)計(jì)方案是將相同邏輯抽出來,實(shí)現(xiàn)重用。

xiaoMing liLei 兩位同學(xué)舉例。這兩位同學(xué)有自己的名字,并且會介紹自己。抽象為程序?qū)ο螅梢宰鋈缦卤硎尽?/p>

var xiaoMing = {
  name : "xiaoMing",
  hello : function(){
    console.log( "Hello, my name is "+ this.name + ".");
  }
}

var liLei = {
  name : "liLei",
  hello : function(){
    console.log( "Hello, my name is "+ this.name  + ".");
  }
}

使用過 java 的同學(xué),可能第一眼就想到了用面向?qū)ο髞斫鉀Q這個(gè)問題。創(chuàng)造一個(gè) Person 的類,然后實(shí)例化 xiaoMingliLei 兩個(gè)對象。在 ES6 中也有類似于 java 中類的概念:class。

下面使用 ES6 的語法,用面向?qū)ο蟮乃悸穪碇貥?gòu)上面的代碼。

class Person {
  constructor(name){
    this.name = name
  }

  hello(){
    console.log(this.name);
  }
}

var xiaoMing = new Person("xiaoMing");
var liLei = new Person("liLei");

可以看到,使用類創(chuàng)建對象,達(dá)到了重用的目的。它基于的邏輯是,兩個(gè)或多個(gè)對象的結(jié)構(gòu)功能類似,可以抽象出一個(gè)模板,依照模板復(fù)制出多個(gè)相似的對象。

使用類創(chuàng)建對象,就像自行車制造商一遍一遍地重用相同的藍(lán)圖來制造大量的自行車。

然解決重用問題的方案,當(dāng)然不止一種。傳統(tǒng)面向?qū)ο蟮念?,只是其中的一種方案。下面輪到我們的主角“原型繼承”登場了,它從另一個(gè)角度解決了重用的問題。

原型繼承的原理 原型對象

JavaScript 中的 object 由兩部分組成,普通屬性的集合,和原型屬性。

var o = {
  a : "a",
  ...
  __proto__: prototypeObj
}

普通屬性指的就是 a;原型屬性 指的是 __proto__。這本不屬于規(guī)范的一部分,后來 chrome 通過 __proto__ 將這個(gè)語言底層屬性給暴露出來了,慢慢的被大家所接受,也就添加到 ES6 規(guī)范中了。 o.__proto__ 的值 prototypeObj 也就是 原型對象 。原型對象其實(shí)也就是一個(gè)普通對象,之所以叫原型對象的原因,只是因?yàn)樗窃蛯傩运傅闹怠?/p>

原型對象所以特殊,是因?yàn)樗鼡碛幸粋€(gè)普通對象沒有的能力:將它的屬性共享給其他對象。

在 ES6 規(guī)范 中,對它是如下定義的:

object that provides shared properties for other objects
屬性讀操作

回到最開始的例子,看看如何利用原型繼承實(shí)現(xiàn)重用的目的。

var prototypeObj = {
  hello: function(){
    console.log( "Hello, my name is "+ this.name  + ".");
  }
  // ...
}

var xiaoMing = {
  name : "xiaoMing",
  __proto__ : prototypeObj
}

var liLei = {
  name : "liLei",
  __proto__ :  prototypeObj
}

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello();  // Hello, my name is liLei.

xiaoMing liLei 對象上,并沒直接擁有 hello 屬性(方法),但是卻能讀取該屬性(執(zhí)行該方法),這是為什么?

想象一個(gè)場景,你在做數(shù)學(xué)作業(yè),遇到一個(gè)很難的題目,你不會做。而你有一個(gè)好兄弟,數(shù)學(xué)很厲害,你去請教他,把這道題做出來了。

xiaoMing 對象上,沒有 hello 屬性,但是它有一個(gè)好兄弟,prototypeObj。屬性讀操作,在 xiaoMing 身上沒有找到 hello 屬性,就會去問它的兄弟 prototypeObj。所以 hello 方法會被執(zhí)行。

原型鏈

還是做數(shù)學(xué)題的例子。你的數(shù)學(xué)題目很難,你的兄弟也沒有答案,他推薦你去問另外一個(gè)同學(xué)。這樣直到有了答案或者再也沒有人可以問,你就不會再問下去。這樣就好像有一條無形鏈條把你和同學(xué)們牽在了一起。

在 JS 中,讀操作通過 __proto__ 會一層一層鏈下去的結(jié)構(gòu),就叫 原型鏈

var deepPrototypeObj = {
  hello: function(){
    console.log( "Hello, my name is "+ this.name  + ".");
  }
  __proto__ : null
}

var prototypeObj = {
  __proto__ : deepPrototypeObj
}

var xiaoMing = {
  name : "xiaoMing",
  __proto__ : prototypeObj
}

var liLei = {
  name : "liLei",
  __proto__ :  prototypeObj
}

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello();  // Hello, my name is liLei.
原型繼承的實(shí)現(xiàn)

在上面的例子中,通過直接修改了 __proto__ 屬性值,實(shí)現(xiàn)了原型繼承。但是在實(shí)際生產(chǎn)中,
用這種方式來改變和繼承屬性是對性能影響非常嚴(yán)重的,所以并不推薦。

代替的方式是使用 Object.create() 方法。

調(diào)用 Object.create() 方法會創(chuàng)建一個(gè)新對象,同時(shí)指定該對象的原型對象為傳入的第一個(gè)參數(shù)。

我們將上面的例子改一下。

var prototypeObj = {
  hello: function(){
    console.log( "Hello, my name is "+ this.name  + ".");
  }
  // ...
}

var xiaoMing = Object.create(prototypeObj);
var liLei = Object.create(prototypeObj);

xiaoMing.name = "xiaoMing";
liLei.name = "liLei";

xiaoMing.hello(); // Hello, my name is xiaoMing.
liLei.hello();  // Hello, my name is liLei.

You-Dont-Know-JS 的作者,對這種原型繼承的實(shí)現(xiàn)取了一個(gè)很好玩的名字 OLOO (objects-linked-to-other-objects) ,這種實(shí)現(xiàn)方式的優(yōu)點(diǎn)是沒有使用任何類的概念,只有 object,所以它是很符合 javaScript 的特性的。

因?yàn)镴S 中本無類,只有 object。

無奈的是,喜歡類的程序員是在太多,所以在 ES6 新增了 class 概念。下一篇會講 class 在 JS 中的實(shí)現(xiàn)原理

小結(jié)

通過類來創(chuàng)建對象,使得開發(fā)者不必寫重復(fù)的代碼,以達(dá)到代碼重用的目的。它基于的邏輯是,兩個(gè)或多個(gè)對象的結(jié)構(gòu)功能類似,可以抽象出一個(gè)模板,依照模板復(fù)制出多個(gè)相似的對象。就像自行車制造商一遍一遍地重用相同的藍(lán)圖來制造大量的自行車。

使用原型繼承,同樣可以達(dá)到重用的目的。它基于的邏輯是,兩個(gè)或多個(gè)對象的對象有一部分共用屬性,可以將共用的屬性抽象到另一個(gè)獨(dú)立公共對象上,通過特殊的原型屬性,將公共對象和普通對象鏈接起來,再利用屬性讀(寫)規(guī)則進(jìn)行遍歷查找,實(shí)現(xiàn)屬性共享。

參考文章

ES6 規(guī)范

You-Dont-Know-JS

MDN Object.create()

JavaScript difference between proto and prototype

proto VS. prototype in JavaScript

JavaScript. The core

Understanding "Prototypes" in JavaScript

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/86779.html

Failed to recv the data from server completely (SIZE:0/8, REASON:closed)