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

資訊專欄INFORMATION COLUMN

__proto__ 屬性與 ES6 classes 的繼承

newsning / 1945人閱讀

摘要:即是由此我們可以輕松偽造一個(gè)實(shí)例對(duì)象可是這是對(duì)對(duì)象的屬性的修改,和有什么關(guān)系靜態(tài)方法的繼承少年,可別忘了函數(shù)本身也是個(gè)對(duì)象喲在上面的代碼中,我們使無關(guān)對(duì)象的指向構(gòu)造函數(shù)的,于是使被判定為的實(shí)例。

關(guān)于 __proto__ 屬性,MDN 上的解釋是這樣的[1]

The __proto__ property of Object.prototype is an accessor property (a getter function and a setter function) that exposes the internal [[Prototype]] (either an object or null) of the object through which it is accessed.

即是說,__proto__ 屬性指向了實(shí)例對(duì)象的原型 Constructor.prototype。那么,這個(gè)屬性里隱藏著怎樣的黑魔法呢?

ES6 class 的實(shí)現(xiàn)

最近看 ECMAScript 6 的 spec,發(fā)現(xiàn)了一些有意思的東西,比如 class 章節(jié):

14.5.14 Runtime Semantics: ClassDefinitionEvaluation[2.1]

With parameter className.
ClassTail : ClassHeritageopt { ClassBodyopt }
...

6.g (for class heritage)

If superclass has a [[FunctionKind]] internal slot whose value is "generator", throw a TypeError exception.

Let protoParent be Get(superclass, "prototype").

ReturnIfAbrupt(protoParent).

If Type(protoParent) is neither Object nor Null, throw a TypeError exception.

Let constructorParent be superclass.

7. Let proto be ObjectCreate(protoParent).

...

12. Let constructorInfo be the result of performing DefineMethod for constructor with arguments proto and constructorParent as the optional functionPrototype argument.

...

16. Perform MakeConstructor(F, false, proto).

...

18. Perform CreateMethodProperty(proto, "constructor", F).

...

這幾行規(guī)定了類繼承(class SubClass extends SuperClass {})的行為,除了眾所周知的 SubClass.prototype = Object.create(SuperClass.prototype) 以外,還做了一件有趣的事:Let constructorParent be superclass, proto be ObjectCreate(protoParent), and performing DefineMethod for constructor with arguments proto and constructorParent as the optional functionPrototype argument.

追溯 functionPrototype 變量的去向,發(fā)現(xiàn)是這樣的:

14.3.8 Runtime Semantics: DefineMethod[2.2]

With parameters object and optional parameter functionPrototype.
...

6. Let closure be FunctionCreate(kind, StrictFormalParameters, FunctionBody, scope, strict). If functionPrototype was passed as a parameter then pass its value as the functionPrototype optional argument of FunctionCreate.

...

9.2.5 FunctionCreate (kind, ParameterList, Body, Scope, Strict, prototype)[2.3]

The abstract operation FunctionCreate requires the arguments: kind which is one of (Normal, Method, Arrow), a parameter list production specified by ParameterList, a body production specified by Body, a Lexical Environment specified by Scope, a Boolean flag Strict, and optionally, an object prototype.
...

4. Let F be FunctionAllocate(prototype, Strict, allocKind).

...

9.2.3 FunctionAllocate (functionPrototype, strict [,functionKind] )[2.4]

...

12. Set the [[Prototype]] internal slot of F to functionPrototype.

...

原來 functionPrototype 被用作了 SubClass 的 [[Prototype]] 屬性!

Babel[2] 對(duì)繼承的實(shí)現(xiàn)如下:

function _inherits(subClass, superClass) {
    if (typeof superClass !** "function" && superClass !** null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

道理我都懂,可是為什么要這樣做?

[[prototype]] 與原型鏈

要檢測一個(gè)對(duì)象是否是一個(gè)構(gòu)造函數(shù)的實(shí)例,我們通常會(huì)用 O instanceof C 這樣的表達(dá)式,在 spec 中,instanceof 運(yùn)算符這樣被定義:

12.9.4 Runtime Semantics: InstanceofOperator(O, C)[2.5]

...

2. Let instOfHandler be GetMethod(C,@@hasInstance).

...

19.2.3.6 Function.prototype[@@hasInstance] ( V )[2.6]


Let F be the this value.

Return OrdinaryHasInstance(F, V).

7.3.19 OrdinaryHasInstance (C, O)[2.6]

...

4. Let P be Get(C, "prototype").

...

7. Repeat

Let O be O.[[GetPrototypeOf]]().

ReturnIfAbrupt(O).

If O is null, return false.

If SameValue(P, O) is true, return true.

9.1.1 [[GetPrototypeOf]] ( )[2.6]

Return the value of the [[Prototype]] internal slot of O.

大致描述如下:instanceof 運(yùn)算符掉用了 Function.prototype 上的內(nèi)部方法 @@hasInstance,此方法將 this 對(duì)象(即 C)的 prototype 屬性與實(shí)例對(duì)象 O 的 [[prototype]] 對(duì)比,如果后者 [[prototype]]null 則返回 false,如果兩者相等,則返回 true,否則沿原型鏈向上比較,直到得出結(jié)果。

即是:

O instanceof C =>
  O.__proto__ === C.prototype ? true:
    O.__proto__.__proto__ === C.prototype ? true :
        ...

由此我們可以輕松偽造一個(gè)實(shí)例對(duì)象:

class A {
    whoami() {
        return "Instance of A";
    }
}

let a = new A();

let b = {};
Object.setPrototypeOf(b, A.prototype); // b.__proto__ = A.prototype

a.whoami() =** b.whoami(); // true
b instanceof A; // true

可是這是對(duì)對(duì)象的 __proto__ 屬性的修改,和 SubClass.__proto__ 有什么關(guān)系?

靜態(tài)方法的繼承

少年,可別忘了 JavaScript 函數(shù)本身也是個(gè)對(duì)象喲!

在上面的代碼中,我們使無關(guān)對(duì)象 b__proto__ 指向構(gòu)造函數(shù) Aprototype,于是使 b 被判定為 A 的實(shí)例。同時(shí),A 的所有原型方法都被 b 所繼承!

換句話說,如果將 SubClass__proto__ 屬性指向 SuperClass,父類上的所有屬性都將被子類繼承!比如:

class A {
    static whoami() {
        return "A Constructor!";
    }

    greet() {
        return "hello world!";
    }
}

function B() {}
Object.setPrototypeOf(B, A);

B.whoami(); // "A Constructor!"

此時(shí),我們?cè)賹?B.prototype__proto__ 屬性指向 A.prototype,即可完成原型方法的繼承:

Object.setPrototypeOf(B.prototype, A.prototype);

let b = new B();
b.greet(); // "hello world!"

b instanceof B; // true
b instanceof A; // true

如此一來,子類就構(gòu)造完成了!可以開開心心造孩子去了!

惡搞:讓函數(shù) B 成為函數(shù) A 的實(shí)例

利用 instanceof 運(yùn)算符的定義,我們還能玩出一些神奇的事,比如:

function A() {};
A.prototype = A;

function B() {};
Object.setPrototypeOf(B, A);

B instanceof A; // true!

(全文完)

參考資料

Object.prototype.__proto__ - JavaScript | MDN

ECMAScript 2015 Language Specification

Babel · The compiler for writing next generation JavaScript

重編自我的博客,原文地址:https://idiotwu.me/proto-property-and-es6-classes-inheritance/

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

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

相關(guān)文章

  • 再和“面向?qū)ο蟆闭剳賽?- 繼承(五)

    摘要:面向?qū)ο罄镒畲蟮奶攸c(diǎn)應(yīng)該就屬繼承了。在第二篇文章里說過原型實(shí)例跟構(gòu)造函數(shù)之間的繼承,并且還講了一道推算題。 通過上一篇文章想必各位老鐵已經(jīng)熟悉了class了,這篇文章接著介紹繼承。面向?qū)ο罄镒畲蟮奶攸c(diǎn)應(yīng)該就屬繼承了。一個(gè)項(xiàng)目可能需要不斷的迭代、完善、升級(jí)。那每一次的更新你是要重新寫呢,還是在原有的基礎(chǔ)上改吧改吧呢?當(dāng)然,不是缺心眼的人肯定都會(huì)在原來的基礎(chǔ)上改吧改吧,那這個(gè)改吧改吧就需要...

    Airmusic 評(píng)論0 收藏0
  • ES6 中Class創(chuàng)建對(duì)象繼承實(shí)現(xiàn)

    摘要:使用類創(chuàng)建實(shí)例對(duì)象也是直接對(duì)類使用命令,跟中構(gòu)造函數(shù)的用法一致。中沒有構(gòu)造函數(shù),作為構(gòu)造函數(shù)的語法糖,同時(shí)有屬性和屬性,因此同時(shí)存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。 1 Class in ES6 ES6提出了類(Class)的概念,讓對(duì)象的原型的寫法更像面向?qū)ο笳Z言寫法。 ES6中通過class定義對(duì)象,默認(rèn)具有constructor方法和自定義方法,但是包含...

    zhou_you 評(píng)論0 收藏0
  • ES6 中Class創(chuàng)建對(duì)象繼承實(shí)現(xiàn)

    摘要:使用類創(chuàng)建實(shí)例對(duì)象也是直接對(duì)類使用命令,跟中構(gòu)造函數(shù)的用法一致。中沒有構(gòu)造函數(shù),作為構(gòu)造函數(shù)的語法糖,同時(shí)有屬性和屬性,因此同時(shí)存在兩條繼承鏈。子類的屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。 1 Class in ES6 ES6提出了類(Class)的概念,讓對(duì)象的原型的寫法更像面向?qū)ο笳Z言寫法。 ES6中通過class定義對(duì)象,默認(rèn)具有constructor方法和自定義方法,但是包含...

    wind5o 評(píng)論0 收藏0
  • oop

    摘要:也就是說,的構(gòu)造函數(shù),對(duì)應(yīng)的類的構(gòu)造方法。上面代碼表明,類的數(shù)據(jù)類型就是函數(shù),類本身就指向構(gòu)造函數(shù)。使用的時(shí)候,也是直接對(duì)類使用命令,跟構(gòu)造函數(shù)的用法完全一致。 OOP 標(biāo)簽(空格分隔): 未分類 ES5 構(gòu)造函數(shù)(constructor),其實(shí)就是一個(gè)普通函數(shù),但是內(nèi)部使用了this變量,對(duì)構(gòu)造函數(shù)使用new運(yùn)算符,就能生成實(shí)例,并且this變量會(huì)綁定在實(shí)例對(duì)象上。 var cat...

    Gu_Yan 評(píng)論0 收藏0
  • ES6 class繼承super關(guān)鍵詞深入探索

    摘要:請(qǐng)看對(duì)應(yīng)版本干了什么可知,相當(dāng)于以前在構(gòu)造函數(shù)里的行為。這種寫法會(huì)與上文中寫法有何區(qū)別我們?cè)诃h(huán)境下運(yùn)行一下,看看這兩種構(gòu)造函數(shù)的有何區(qū)別打印結(jié)果打印結(jié)果結(jié)合上文中關(guān)于原型的論述,仔細(xì)品味這兩者的差別,最好手動(dòng)嘗試一下。 ES6 class 在ES6版本之前,JavaScript語言并沒有傳統(tǒng)面向?qū)ο笳Z言的class寫法,ES6發(fā)布之后,Babel迅速跟進(jìn),廣大開發(fā)者也很快喜歡上ES6帶...

    jubincn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<