国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【Step-By-Step】高頻面試題深入解析 / 周刊06

LiuRhoRamen / 813人閱讀

摘要:實例擁有構造函數屬性,該屬性返回創建實例對象的構造函數。在考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。在子類的構造函數中,只有調用之后,才能使用關鍵字,否則報錯。

不積跬步無以至千里。

關于【Step-By-Step】
Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發布一道面試題。

每個周末我會仔細閱讀大家的答案,整理最一份較優答案出來,因本人水平有限,有誤的地方,大家及時指正。

如果想 加群 學習,可以通過文末的公眾號,添加我為好友。

更多優質文章可戳: https://github.com/YvetteLau/...

本周面試題一覽:

原型鏈繼承的基本思路是什么?有什么優缺點?

借用構造函數和組合繼承基本思路是什么?有什么優缺點?

原型式繼承的基本思路是什么?有什么優缺點?

寄生式繼承的基本思路是什么?有什么優缺點?

寄生組合式繼承的基本思路是什么?有什么優缺點?

本周是繼承專題,在開始之前,需要先了解構造函數、原型和原型鏈的相關知識。

構造函數

構造函數和普通函數的區別僅在于調用它們的方式不同,任何函數,只要通過 new 操作符來調用,那它就可以作為構造函數;任何函數,如果不通過 new 操作符來調用,那么它就是一個普通函數。

實例擁有 constructor(構造函數) 屬性,該屬性返回創建實例對象的構造函數。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

var Yvette = new Person("劉小夕", 20);
console.log(Yvette.constructor === Person); //true

有一點需要說明的是,除了基本數據類型的 constructor 外( nullundefinedconstructor 屬性),constructor 屬性是可以被重寫的。因此檢測對象類型時,instanceof 操作符比 contsrutor 更可靠一些。

function Person(name) {
    this.name = name;
}
function SuperType() { }
var Yvette = new Person("劉小夕");
console.log(Yvette.constructor); //[Function: Person]
Yvette.constructor = SuperType;
console.log(Yvette.constructor); //[Function: SuperType]
原型

我們創建的每個函數都有 prototype 屬性,這個屬性指向函數的原型對象。原型對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。

在默認情況下,所有原型對象都會自動獲得一個 constructor 屬性,這個屬性包含一個指向 prototype 屬性所在函數的指針。

當調用構造函數創建一個新實例后,該實例的內部將包含一個指針,指向構造函數的原型對象(可以通過實例的 __proto__ 來訪問構造函數的原型對象)。

function Person(name) {
    this.name = name;
}
Person.prototype.sayName = function() {
    console.log(this.name);
}
var person1 = new Person("劉小夕");
var person2 = new Person("前端小姐姐");
//構造函數原型對象上的方法和屬性被實例共享
person1.sayName();
person1.sayName(); 

實例.__proto__ === 構造函數.prototype

原型鏈

簡單回顧一下構造函數、原型和實例的關系:

每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個可以執行原型對象的內部指針(可以通過 __proto 訪問)。

假如我們讓原型對象等于另一個類型的實例,那么此時原型對象包含一個指向另一個原型的指針,相應地,另一個原型中也包含著一個指向另一個構造函數的指針。加入另一個原型又是另一個類型的實例,那么上述關系仍然成立,如此層層遞進,就構成了實例與原型的鏈條,這就是原型鏈的基本概念。

function SuperType() {
    this.type = "animal";
}
SuperType.prototype.getType = function() {
    console.log(this.type);
}
function SubType() {

}
SubType.prototype = new SuperType();
SubType.prototype.sayHello = function() {
    console.log("hello");
}
function SimType(name) {
    this.name = name;
}
SimType.prototype = new SubType();
SimType.prototype.sayHi = function() {
    console.log("hi");
}
var instance = new SimType("劉小夕");
instance.getType();

一圖勝萬言:

調用 instance.getType() 會調用以下的搜索步驟:

搜索 instance 實例

搜索 SimType.prototype

搜索 SubType.prototype

搜索 SuperType.prototype,找到了 getType 方法

在找不到屬性或方法的情況下,搜索過程總是要一環一環地前行到原型鏈的末端才會停下來。

所有引用類型都繼承了 Object,這個繼承也是通過原型鏈實現的。如果在 SuperType.prototype 還沒有找到 getType,就會到 Object.prototype中找(圖中少畫了一環)。

25. 原型鏈繼承

原型鏈繼承的基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。

SubType.prototype = new SuperType();

function SuperType() {
    this.name = "Yvette";
    this.colors = ["pink", "blue", "green"];
}
SuperType.prototype.getName = function () {
    return this.name;
}
function SubType() {
    this.age = 22;
}
SubType.prototype = new SuperType();
SubType.prototype.getAge = function() {
    return this.age;
}
SubType.prototype.constructor = SubType;
let instance1 = new SubType();
instance1.colors.push("yellow");
console.log(instance1.getName()); //"Yvette"
console.log(instance1.colors);//[ "pink", "blue", "green", "yellow" ]

let instance2 = new SubType();
console.log(instance2.colors);//[ "pink", "blue", "green", "yellow" ]

可以看出 colors 屬性會被所有的實例共享(instance1、instance2、...)。

缺點:

通過原型來實現繼承時,原型會變成另一個類型的實例,原先的實例屬性變成了現在的原型屬性,該原型的引用類型屬性會被所有的實例共享。

在創建子類型的實例時,沒有辦法在不影響所有對象實例的情況下給超類型的構造函數中傳遞參數。

26. 借用構造函數

借用構造函數的技術,其基本思想為:

在子類型的構造函數中調用超類型構造函數。

function SuperType(name) {
    this.name = name;
    this.colors = ["pink", "blue", "green"];
}
function SubType(name) {
    SuperType.call(this, name);
}
let instance1 = new SubType("Yvette");
instance1.colors.push("yellow");
console.log(instance1.colors);//["pink", "blue", "green", yellow]

let instance2 = new SubType("Jack");
console.log(instance2.colors); //["pink", "blue", "green"]
優點:

可以向超類傳遞參數

解決了原型中包含引用類型值被所有實例共享的問題

缺點:

方法都在構造函數中定義,函數復用無從談起,另外超類型原型中定義的方法對于子類型而言都是不可見的。

27. 組合繼承

組合繼承指的是將原型鏈和借用構造函數技術組合到一塊,從而發揮二者之長的一種繼承模式?;舅悸罚?/p>

使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承,既通過在原型上定義方法來實現了函數復用,又保證了每個實例都有自己的屬性。

function SuperType(name) {
    this.name = name;
    this.colors = ["pink", "blue", "green"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
}
function SuberType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}
SuberType.prototype = new SuperType();
SuberType.prototype.constructor = SuberType;
SuberType.prototype.sayAge = function () {
    console.log(this.age);
}
let instance1 = new SuberType("Yvette", 20);
instance1.colors.push("yellow");
console.log(instance1.colors); //[ "pink", "blue", "green", "yellow" ]
instance1.sayName(); //Yvette

let instance2 = new SuberType("Jack", 22);
console.log(instance2.colors); //[ "pink", "blue", "green" ]
instance2.sayName();//Jack
缺點:

無論什么情況下,都會調用兩次超類型構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數內部。

優點:

可以向超類傳遞參數

每個實例都有自己的屬性

實現了函數復用

28. 原型式繼承

原型繼承的基本思想:

借助原型可以基于已有的對象創建新對象,同時還不必因此創建自定義類型。

function object(o) {
    function F() { }
    F.prototype = o;
    return new F();
}

object() 函數內部,先穿甲一個臨時性的構造函數,然后將傳入的對象作為這個構造函數的原型,最后返回了這個臨時類型的一個新實例,從本質上講,object() 對傳入的對象執行了一次淺拷貝。

ECMAScript5通過新增 Object.create()方法規范了原型式繼承。這個方法接收兩個參數:一個用作新對象原型的對象和(可選的)一個為新對象定義額外屬性的對象(可以覆蓋原型對象上的同名屬性),在傳入一個參數的情況下,Object.create()object() 方法的行為相同。

var person = {
    name: "Yvette",
    hobbies: ["reading", "photography"]
}
var person1 = Object.create(person);
person1.name = "Jack";
person1.hobbies.push("coding");
var person2 = Object.create(person);
person2.name = "Echo";
person2.hobbies.push("running");
console.log(person.hobbies);//[ "reading", "photography", "coding", "running" ]
console.log(person1.hobbies);//[ "reading", "photography", "coding", "running" ]

在沒有必要創建構造函數,僅讓一個對象與另一個對象保持相似的情況下,原型式繼承是可以勝任的。

缺點:

同原型鏈實現繼承一樣,包含引用類型值的屬性會被所有實例共享。

29. 寄生式繼承

寄生式繼承是與原型式繼承緊密相關的一種思路。寄生式繼承的思路與寄生構造函數和工廠模式類似,即創建一個僅用于封裝繼承過程的函數,該函數在內部已某種方式來增強對象,最后再像真地是它做了所有工作一樣返回對象。

function createAnother(original) {
    var clone = object(original);//通過調用函數創建一個新對象
    clone.sayHi = function () {//以某種方式增強這個對象
        console.log("hi");
    };
    return clone;//返回這個對象
}
var person = {
    name: "Yvette",
    hobbies: ["reading", "photography"]
};

var person2 = createAnother(person);
person2.sayHi(); //hi

基于 person 返回了一個新對象 -—— person2,新對象不僅具有 person 的所有屬性和方法,而且還有自己的 sayHi() 方法。在考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。

缺點:

使用寄生式繼承來為對象添加函數,會由于不能做到函數復用而效率低下。

同原型鏈實現繼承一樣,包含引用類型值的屬性會被所有實例共享。

30. 寄生組合式繼承

所謂寄生組合式繼承,即通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法,基本思路:

不必為了指定子類型的原型而調用超類型的構造函數,我們需要的僅是超類型原型的一個副本,本質上就是使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。寄生組合式繼承的基本模式如下所示:

function inheritPrototype(subType, superType) {
    var prototype = object(superType.prototype); //創建對象
    prototype.constructor = subType;//增強對象
    subType.prototype = prototype;//指定對象
}

第一步:創建超類型原型的一個副本

第二步:為創建的副本添加 constructor 屬性

第三步:將新創建的對象賦值給子類型的原型

至此,我們就可以通過調用 inheritPrototype 來替換為子類型原型賦值的語句:

function SuperType(name) {
    this.name = name;
    this.colors = ["pink", "blue", "green"];
}
//...code
function SuberType(name, age) {
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SuberType, SuperType);
//...code
優點:

只調用了一次超類構造函數,效率更高。避免在SuberType.prototype上面創建不必要的、多余的屬性,與其同時,原型鏈還能保持不變。

因此寄生組合繼承是引用類型最理性的繼承范式。

ES6 繼承

Class 可以通過extends關鍵字實現繼承,如:

class SuperType {
    constructor(age) {
        this.age = age;
    }

    getAge() {
        console.log(this.age);
    }
}

class SubType extends SuperType {
    constructor(age, name) {
        super(age); // 調用父類的constructor(x, y)
        this.name = name;
    }

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

let instance = new SubType(22, "劉小夕");
instance.getAge(); //22

對于ES6的 class 需要做以下幾點說明:

類的數據類型就是函數,類本身就指向構造函數。

console.log(typeof SuperType);//function
console.log(SuperType === SuperType.prototype.constructor); //true

類的內部所有定義的方法,都是不可枚舉的。(ES5原型上的方法默認是可枚舉的)

Object.keys(SuperType.prototype);

constructor 方法是類的默認方法,通過 new 命令生成對象實例時,自動調用該方法。一個類必須有constructor 方法,如果沒有顯式定義,一個空的 constructor 方法會被默認添加。

Class 不能像構造函數那樣直接調用,會拋出錯誤。

使用 extends 關鍵字實現繼承,有一點需要特別說明:

子類必須在 constructor 中調用 super 方法,否則新建實例時會報錯。如果沒有子類沒有定義 constructor 方法,那么這個方法會被默認添加。在子類的構造函數中,只有調用 super 之后,才能使用 this關鍵字,否則報錯。這是因為子類實例的構建,基于父類實例,只有super方法才能調用父類實例。

class SubType extends SuperType {
    constructor(...args) {
        super(...args);
    }
}
參考文章:

[1] 珠峰架構課(墻裂推薦)

[2] CSS-清除浮動

[3] 詳解JS函數柯里化

[4] JavaScript數組去重

謝謝各位小伙伴愿意花費寶貴的時間閱讀本文,如果本文給了您一點幫助或者是啟發,請不要吝嗇你的贊和Star,您的肯定是我前進的最大動力。 https://github.com/YvetteLau/...

關注公眾號,加入技術交流群。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105248.html

相關文章

  • Step-By-Step高頻面試深入解析 / 周刊05

    摘要:關于點擊進入項目是我于開始的一個項目,每個工作日發布一道面試題。那個率先改變的實例的返回值,就傳遞給的回調函數。通過插入標簽的方式來實現跨域,參數只能通過傳入,僅能支持請求。因此清除浮動,只需要觸發一個即可。 關于【Step-By-Step】 Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發布一道面試題。每個周末我會仔細閱讀大家的...

    xiangchaobin 評論0 收藏0
  • Step-By-Step高頻面試深入解析 / 周刊04

    摘要:關于點擊進入項目是我于開始的一個項目,每個工作日發布一道面試題。的狀態由決定,分成以下兩種情況只有的狀態都變成,的狀態才會變成,此時的返回值組成一個數組,傳遞給的回調函數。 關于【Step-By-Step】 Step-By-Step (點擊進入項目) 是我于 2019-05-20 開始的一個項目,每個工作日發布一道面試題。每個周末我會仔細閱讀大家的答案,整理最一份較優答案出來,因本人...

    youkede 評論0 收藏0

發表評論

0條評論

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