成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解 JavaScript 中的 class

Vicky / 1094人閱讀

摘要:在規(guī)范中,引入了的概念。使用中的聲明一個類,是非常簡單的事。中面向?qū)ο髮嵗谋澈笤恚瑢嶋H上就是原型對象。與區(qū)別理解上述原理后,還需要注意與屬性的區(qū)別。實際上,在中,類繼承的本質(zhì)依舊是原型對象。

在 ES6 規(guī)范中,引入了 class 的概念。使得 JS 開發(fā)者終于告別了,直接使用原型對象模仿面向?qū)ο笾械念惡皖惱^承時代。

但是JS 中并沒有一個真正的 class 原始類型, class 僅僅只是對原型對象運用語法糖。所以,只有理解如何使用原型對象實現(xiàn)類和類繼承,才能真正地用好 class

ES6:class

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

使用 ES6 中的 class 聲明一個類,是非常簡單的事。它的語法如下:

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

  hello(){
    console.log("Hello, my name is " + this.name + ".");
  }
}

var xiaoMing = new Person("xiaoMing");
xiaoMing.hello() // Hello, my name is xiaoMing.

xiaoMing 是通過類 Person 實例化出來的對象。對象 xiaoMing 是按照類 Person 這個模板,實例化出來的對象。實例化出來的對象擁有類預(yù)先訂制好的結(jié)構(gòu)和功能。

ES6 的語法很簡單,但是在實例化的背后,究竟是什么在起作用呢?

class 實例化的背后原理

使用 class 的語法,讓開發(fā)者告別了使用 prototype 模仿面向?qū)ο蟮臅r代。但是,class 并不是 ES6 引入的全新概念,它的原理依舊是原型繼承。

typeof class == "function"

通過類型判斷,我們可以得知,class 的并不是什么全新的數(shù)據(jù)類型,它實際只是 function (或者說 object)。

class Person {
  // ...
}

typeof Person // function

為了更加直觀地了解 Person 的實質(zhì),可以將它在控制臺打印出來,如下。

Person 的屬性并不多,除去用 [[...]] 包起來的內(nèi)置屬性外,大部分屬性根據(jù)名字就能明白它的作用。需要我們重點關(guān)注的是 prototype__proto__ 兩個屬性。

(關(guān)于 __proto__ 可以在本文的姊妹篇 找到答案)

實例化的原理: prototype

先來講講 prototype 屬性,它指向一個特殊性對象:原型對象。

原型對象所以特殊,是因為它擁有一個普通對象沒有的能力:將它的屬性共享給其他對象。

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

object that provides shared properties for other objects

原型對象是如何將它的屬性分享給其他對象的呢?

這里使用 ES5 創(chuàng)建一個類,并將它實例化,來看看它的實質(zhì)。

function Person() {
  this.name = name
}

// 1. 首先給 Person.prototype 原型對象添加了 describe 方法 。
Person.prototype.describe = function(){
  console.log("Hello, my name is " + this.name + ".");
}

// 2. 實例化對象的 __proto__ 指向 Person.prototype
var jane = new Person("jane");
jane.__proto__ === Person.prototype;


// 3. 讀取 describe 方法時,實際會沿著原型鏈查找到 Person.prototype 原型對象上。
jane.describe() // Hello, my name is jane.

上述使用 JS 模仿面向?qū)ο髮嵗谋澈?,實際有三個步驟:

首先給 Person.prototype 屬性所指的原型對象上添加了一個方法 describe

在使用 new 關(guān)鍵字創(chuàng)建對象時,會默認(rèn)給該對象添加一個原型屬性 __proto__,該屬性指向 Person.prototype 原型對象。

在讀取 describe 方法時,首先會在 jane 對象查找該方法,但是 jane 對象并不直接擁有 describe 方法。所以會沿著原型鏈查找到 Person.prototype 原型對象上,最后返回該原型對象的 describe 方法。

JS 中面向?qū)ο髮嵗谋澈笤?,實際上就是 原型對象。

為了方便大家理解,從網(wǎng)上扒了一張的圖片,放到這來便于大家理解。

prototype__proto__ 區(qū)別

理解上述原理后,還需要注意 prototype__proto__ 屬性的區(qū)別。

__proto__ 所指的對象,真正將它的屬性分享給它所屬的對象。所有的對象都有 __proto__ 屬性,它是一個內(nèi)置屬性,被用于繼承。

prototype 是一個只屬于 function 的屬性。當(dāng)使用 new 方法調(diào)用該構(gòu)造函數(shù)的時候,它被用于構(gòu)建新對象的 __proto__。另外它不可寫,不可枚舉,不可配置。

( new Foo() ).__proto__ === Foo.prototype
( new Foo() ).prototype === undefined
class 定義屬性

當(dāng)我們使用 class 定義屬性(方法)的時候,實際上等于是在 class 的原型對象上定義屬性。

class Foo {
  constructor(){ /* constructor */  }

  describe(){ /* describe */  }
}

// 等價于
function Foo (){
  /* constructor */
}

Foo.prototype.describe = function(){  /* describe */  }

constructor 是一個比較特殊的屬性,它指向構(gòu)造函數(shù)(類)本身??梢酝ㄟ^以下代碼驗證。

Foo.prototype.constructor === Foo // true
類繼承

在傳統(tǒng)面向?qū)ο笾?,類是可以繼承類的。這樣子類就可以復(fù)制父類的方法,達(dá)到代碼復(fù)用的目的。

ES6 也提供了類繼承的語法 extends,如下:

class Foo {
  constructor(who){
    this.me = who;
  }

  identify(){
    return "I am " + this.me;
  }
}


class Bar extends Foo {
  constructor(who){
    // super() 指的是調(diào)用父類
    // 調(diào)用的同時,會綁定 this 。
    // 如:Foo.call(this, who)
    super(who);
  }

  speak(){
    alert( "Hello, " + this.identify() + "." );
  }
}

var b1 = new Bar( "b1" );

b1.speak();

當(dāng)實例 b1 調(diào)用 speak 方法時,b1 本身沒有 speak,所以會到 Bar.prototype 原型對象上查找,并且調(diào)用原型對象上的 speak 方法。調(diào)用 identify 方式時,由于 this 指向的是 b1 對象。所以也會先在 b1 本身查找,然后沿著原型鏈,查找 Bar.prototype,最后在 Foo.prototype 原型對象上找到 identify 方法,然后調(diào)用。

實際上,在 JavaScript 中,類繼承的本質(zhì)依舊是原型對象。

他們的關(guān)系如下圖所示:

參考文章

(ES6 規(guī)范)[http://www.ecma-international...

MDN Classes

You-Dont-Know-JS

JavaScript difference between proto and prototype

proto VS. prototype in JavaScript

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

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

相關(guān)文章

  • 深入理解ES6》筆記—— JavaScript中的class(9)

    摘要:新建一個類該函數(shù)返回一個類的實例給函數(shù)傳入通過立即調(diào)用類構(gòu)造函數(shù)可以創(chuàng)建單例。派生類是指繼承自其它類的新類。在構(gòu)造函數(shù)中訪問之前要調(diào)用,負(fù)責(zé)初始化。在構(gòu)造函數(shù)中使用通常表示當(dāng)前的構(gòu)造函數(shù)名。 ES5中的近類結(jié)構(gòu) ES5以及之前的版本,沒有類的概念,但是聰明的JavaScript開發(fā)者,為了實現(xiàn)面向?qū)ο?,?chuàng)建了特殊的近類結(jié)構(gòu)。 ES5中創(chuàng)建類的方法:新建一個構(gòu)造函數(shù),定義一個方法并且賦值...

    gggggggbong 評論0 收藏0
  • 深入理解ES6》筆記—— JavaScript中的class(9)

    摘要:新建一個類該函數(shù)返回一個類的實例給函數(shù)傳入通過立即調(diào)用類構(gòu)造函數(shù)可以創(chuàng)建單例。派生類是指繼承自其它類的新類。在構(gòu)造函數(shù)中訪問之前要調(diào)用,負(fù)責(zé)初始化。在構(gòu)造函數(shù)中使用通常表示當(dāng)前的構(gòu)造函數(shù)名。 ES5中的近類結(jié)構(gòu) ES5以及之前的版本,沒有類的概念,但是聰明的JavaScript開發(fā)者,為了實現(xiàn)面向?qū)ο?,?chuàng)建了特殊的近類結(jié)構(gòu)。 ES5中創(chuàng)建類的方法:新建一個構(gòu)造函數(shù),定義一個方法并且賦值...

    Jason 評論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評論0 收藏0
  • 深入理解 JavaScript 原型繼承

    摘要:下面輪到我們的主角原型繼承登場了,它從另一個角度解決了重用的問題。原型繼承的原理原型對象中的由兩部分組成,普通屬性的集合,和原型屬性。原型繼承的實現(xiàn)在上面的例子中,通過直接修改了屬性值,實現(xiàn)了原型繼承。使用原型繼承,同樣可以達(dá)到重用的目的。 繼承的本質(zhì):重用 在探討 JavaScript 的原型繼承之前,先不妨想想為什么要繼承? 考慮一個場景,如果我們有兩個對象,它們一部分屬性相同,另...

    UCloud 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<