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

資訊專欄INFORMATION COLUMN

Js高級(jí)編程筆記--面向?qū)ο蟮某绦蛟O(shè)計(jì)

gclove / 1684人閱讀

摘要:在沒(méi)有必要?jiǎng)?chuàng)建構(gòu)造函數(shù),只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類似的情況下,原型式繼承是完全可以勝任的。方便我們進(jìn)行面向?qū)ο蟮木幊獭?/p>

理解對(duì)象 屬性類型 1.數(shù)據(jù)屬性

特性:

Configurable : 表示能否通過(guò) delete 刪除屬性,能否修改屬性特性,能否把屬性改為訪問(wèn)器屬性

Enumerable : 表示能否通過(guò) for in 循環(huán)返回

Writable : 表示能否修改屬性的值

Value : 包含屬性的值,讀取或?qū)懭雽?shí)際上操作的是這個(gè)值

2.訪問(wèn)器屬性

特性:

Configurable : 表示能否通過(guò) delete 刪除屬性,能否修改屬性特性,能否把屬性改為訪問(wèn)器屬性

Enumerable : 表示能否通過(guò) for in 循環(huán)返回

Get : 讀取時(shí)調(diào)用的參數(shù).默認(rèn)值為 undefined

Set : 寫入時(shí)調(diào)用的參數(shù)。 默認(rèn)值為 undefined

3.注意:

訪問(wèn)器屬性不能直接定義,必須使用 Object.defineProperty()定義。

修改屬性默認(rèn)的特性,必須使用 Object.defineProperty()方法

get,set,并不一定要定義,只定義 get 為只讀,只定義 set 為只寫不可讀。

定義多個(gè)屬性可以使用 Object.defineProperties()方法

讀取屬性的特性,使用 Object.getOwnPropertyDescriptor()

創(chuàng)建對(duì)象 1.工廠模式

定義一個(gè)方法接受參數(shù),用于創(chuàng)建對(duì)象,并將其返回

function createPerson(name, age) {
    var o = new Object();
    o.name = name;
    o.age = age;
    return o;
}
var person1 = createPerson("andy_chen", 18);
var person2 = createPerson("andy_chen", 18);
工廠模式可以創(chuàng)建多個(gè)相似對(duì)象的問(wèn)題,卻沒(méi)解決對(duì)象識(shí)別的問(wèn)題。例如person1的類型是什么
2.構(gòu)造函數(shù)模式 :
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.sayName = function() {
        alert(this.name);
    };
}
var person1 = new Person("andy_chen", 18);
var person2 = new Person("andy_chen", 18);
person1.sayName();
person2.sayName();
使用 new 操作符。實(shí)際上有以下 4 個(gè)步驟:

創(chuàng)建一個(gè)新對(duì)象

將構(gòu)造函數(shù)的作用域賦給對(duì)象(使 this 指向新對(duì)象)

執(zhí)行構(gòu)造方法(為這個(gè)對(duì)象添加屬性)

返回新對(duì)象

構(gòu)造函數(shù)的問(wèn)題在于,每個(gè)方法都要在每個(gè)實(shí)例中重新創(chuàng)建一遍。即例子中,person1和person2的sayName的不相等的。
但是,完成同樣的功能的方法,卻每個(gè)實(shí)例都要?jiǎng)?chuàng)建一遍,這顯然不合理,所以,又出現(xiàn)了下面的原型模式
3.原型模式: 理解原型對(duì)象

一圖勝千言:

只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype,這個(gè)屬性指向函數(shù)的對(duì)象原型。

對(duì)象原型中,則默認(rèn)有一個(gè) constructor 屬性,指向該新函數(shù)。

通過(guò)新函數(shù)創(chuàng)建的實(shí)例,有一個(gè)[[prototype]]屬性(在 chrome,firefox,safari 中該屬性即為proto),指向了新函數(shù)的 prototype。

注意:該屬性僅僅是執(zhí)行構(gòu)造函數(shù)的 prototype,也即是說(shuō),他們與構(gòu)造函數(shù)沒(méi)有直接聯(lián)系了

讀取某個(gè)對(duì)象的屬性時(shí),會(huì)先在實(shí)例上找,如果沒(méi)找到,則進(jìn)一步在實(shí)例上的 prototype 屬性上找

為實(shí)例添加屬性的時(shí)候會(huì)屏蔽掉原型上屬性。這個(gè)時(shí)候即使置為 null 也沒(méi)法訪問(wèn)到原型上的屬性,只有通過(guò) delete 刪掉之后才可以

XXX.prototype.isPrototype(xxx), 可以用這個(gè)方法判定對(duì)象是否是該實(shí)例的原型對(duì)象

Object.getPrototypeOf() 用這個(gè)可以獲取實(shí)例對(duì)應(yīng)的原型對(duì)象 (ES5 新增方法)

in 操作符

多帶帶使用時(shí): in 操作符 可以確定屬性是否存在于對(duì)象上(無(wú)論是存在于實(shí)例上還是原型上)

用于 for 循環(huán)中時(shí),返回的是所有能夠通過(guò)對(duì)象訪問(wèn)的,可枚舉的屬性。(IE8 中,如果開(kāi)發(fā)者自定義 toString 類似的系統(tǒng)不可枚舉的方法,瀏覽器還是不會(huì)將它遍歷出來(lái))

ES5:Object.keys() 可以返回一個(gè)包含所有可枚舉屬性的字符串?dāng)?shù)組
Object.getOwnPropertyNames() 可以返回所有實(shí)例屬性,無(wú)論是否可枚舉
//原型模式的實(shí)現(xiàn):
function Person() {}

Person.prototype.name = "andy chen";

Person.prototype.sayName = function() {
    alert(this.name);
};
更簡(jiǎn)單的原型語(yǔ)法

重寫整個(gè) prototype,不過(guò)會(huì)導(dǎo)致 constructor 改變。所以需要重新指定 constructor.

//更簡(jiǎn)單的原型語(yǔ)法
function Person() {}
Person.prototype = {
    constructor: Person, //因?yàn)檫@種寫法會(huì)覆蓋掉原來(lái)的Person.prototype,需要重新為constructor賦值
    name: "andy chen",
    sayName: function() {
        alert(this.name);
    }
};
var person1 = new Person();
var person2 = new Person();
原型模式的問(wèn)題:所有實(shí)例都共享一個(gè)prototype,類似上面的例子,person1,person2的name屬性是共享的。如果修改其中一個(gè),會(huì)導(dǎo)致另一個(gè)也受影響。所以,才會(huì)出現(xiàn)下面構(gòu)造函數(shù)與原型模式組合使用
4.組合使用構(gòu)造函數(shù)和原型模式

創(chuàng)建自定義類型最常見(jiàn)的方式就是組合使用構(gòu)造函數(shù)和原型模式

構(gòu)造函數(shù)定義實(shí)例屬性,而原型模式用于定義方法和共享的屬性. 所以,上面的例子可以改寫成這樣:

function Person(name) {
    this.name = name;
}
Person.prototype = {
    constructor: Person,
    sayName: function() {
        alert(this.name);
    }
};
var person1 = new Person("andy chen");
var person2 = new Person("andy chen");

除了使用組合模式創(chuàng)建對(duì)象,還有以下幾種方式,可以針對(duì)不同的情況選擇。

5.動(dòng)態(tài)原型模式

在構(gòu)造方法中,判斷是否是第一次進(jìn)入使用構(gòu)造方法,如果是,則添加一系列的方法到原型上

6.寄生構(gòu)造函數(shù)模式

類基本思想是創(chuàng)建一個(gè)函數(shù),該函數(shù)的作用僅僅是封裝創(chuàng)建對(duì)象的代碼然后再返回新創(chuàng)建的對(duì)象。

7.穩(wěn)妥構(gòu)造函數(shù)模式: 穩(wěn)妥對(duì)象

指的是沒(méi)有公共屬性,而且其方法也不引用 this 對(duì)象。最適合用于一些安全的環(huán)境或者在防止數(shù)據(jù)被其他程序改動(dòng)時(shí)使用

穩(wěn)妥構(gòu)造函數(shù)

遵循與寄生構(gòu)造函數(shù)類似的模式,但有兩點(diǎn)不同:

新創(chuàng)建的對(duì)象實(shí)例不引用 this.

不使用 new 操作符調(diào)用構(gòu)造函數(shù)

繼承

OO 語(yǔ)言一般擁有兩種繼承方式:接口繼承(只繼承方法簽名)以及實(shí)現(xiàn)繼承(繼承實(shí)際方法)
ES 無(wú)法像其他 OO 語(yǔ)言一樣支持接口繼承,只能依靠原型鏈實(shí)現(xiàn) 實(shí)現(xiàn)繼承

1. 原型鏈 要了解原型鏈的概念,先回顧一下構(gòu)造函數(shù),原型和實(shí)例之間的關(guān)系(參考圖 6-1)

每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象包含一個(gè)指向構(gòu)造函數(shù)的指針.

每個(gè)實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針的內(nèi)部屬性(在 chrome 中一般為proto屬性)

那么,如果我們有個(gè)新的構(gòu)造函數(shù),并讓它的原型對(duì)象等于另一個(gè)類型的實(shí)例,結(jié)果會(huì)怎樣.

對(duì)于這個(gè)新的構(gòu)造函數(shù),它的原型對(duì)象就變成了另一個(gè)類型的實(shí)例,而這個(gè)實(shí)例中,又包含一個(gè)內(nèi)部屬性,指向了另一個(gè)原型對(duì)象(該原型對(duì)象內(nèi)部 constructor 指向另一個(gè)構(gòu)造函數(shù)),如果這個(gè)原型對(duì)象又是另一個(gè)類型的實(shí)例,則它又包含了一個(gè)內(nèi)部屬性,繼續(xù)指向上層的原型對(duì)象。這樣層層遞進(jìn),就形成了原型鏈。

如下圖:

特點(diǎn)

在實(shí)例中搜索屬性的時(shí)候,便是基于原型鏈來(lái)搜索的,先搜索實(shí)例,再在原型鏈上一層層往上搜,直到找到或者到原型鏈末端才會(huì)停下來(lái)

由于所有引用類型都繼承了 Object,所以原型鏈的最頂層是 Object

使用原型鏈實(shí)現(xiàn)繼承時(shí),不能使用對(duì)象字面量創(chuàng)建原型方法,因?yàn)檫@樣會(huì)重寫原型鏈

原型鏈實(shí)現(xiàn)繼承的方式:
function Animal() {
    this.name = "animal";
}
Animal.prototype.getName = function() {
    return this.name;
};

function Cat() {
    this.catName = "cat";
}
Cat.prototype = new Animal();

var cat1 = new Cat();
var cat2 = new Cat();
alert(cat1.getName()); //由于第10行,將Cat的原型指向Animal的實(shí)例,因?yàn)閷?shí)例中有指向Animal.prototype的指針。所以,這里可以訪問(wèn)到getName()

cat1.name = "changed name";
alert(cat2.getName());
原型鏈的問(wèn)題:

使用原型鏈,由于是使用新的實(shí)例作為子類型的原型,實(shí)例中卻包含了父類型的屬性,所以原來(lái)父類型的屬性,就都到了子類型的原型上了。這就會(huì)造成子類型的不同實(shí)例會(huì)共享同個(gè)屬性.如上例子中,第 15 行,改變 cat1 實(shí)例的 name 屬性影響到了 cat2 的 name 屬性

創(chuàng)建子類型的時(shí)候,不能向父類型傳遞參數(shù)

2. 借用構(gòu)造函數(shù)

由于原型鏈存在問(wèn)題,所以便出現(xiàn)了借用構(gòu)造函數(shù)的方法
在子類型的構(gòu)造方法中,調(diào)用父類型的構(gòu)造方法:SuperType.call(this); 將父類型的屬性添加到子類型上,并且可以傳遞參數(shù)給父類型

借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承的方式:
function Animal() {
    this.name = "animal";
}
function Cat() {
    Animal.call(this);
}
var cat1 = new Cat();
var cat2 = new Cat();
cat1.name = "changed name";
alert(cat1.name); //changed name
alert(cat2.name); //animal //借用構(gòu)造函數(shù)的方式,各實(shí)例之間的屬性便不會(huì)互相影響
借用構(gòu)造函數(shù)問(wèn)題:

類似創(chuàng)建對(duì)象單純使用構(gòu)造方法一樣,也會(huì)造成公有的方法無(wú)法公用。所以一般也很少多帶帶使用此方式

3. 組合繼承

組合原型鏈以及借用構(gòu)造函數(shù)

使用原型鏈實(shí)現(xiàn)對(duì)原型屬性和方法的繼承

借用構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)對(duì)實(shí)例中屬性的繼承。

function Animal() {
    this.name = "animal";
}
Animal.prototype.getName = function() {
    return this.name;
};

function Cat() {
    Animal.call(this); //借用構(gòu)造函數(shù)
}
Cat.prototype = new Animal(); //原型鏈方式
Cat.prototype.constructor = Cat;

//這里可以
var cat1 = new Cat();
var cat2 = new Cat();
cat1.name = "changed name";

alert(cat1.getName()); //changed name
alert(cat2.getName()); //animal
組合繼承的問(wèn)題:

父類的屬性會(huì)存在于子類型的原型上,導(dǎo)致被不同實(shí)例共享。雖然由于借用構(gòu)造函數(shù)之后,導(dǎo)致實(shí)例上又重寫了這些屬性,所以每個(gè)實(shí)例有各自的屬性。

另外,instanceof 和 isPrototypeOf 能夠識(shí)別基于組合繼承創(chuàng)建的對(duì)象

**組合繼承,并不完美
因?yàn)槲覀冎恍枰^承父類型原型上的屬性而已,不需要父類型實(shí)例的屬性。
還有更好的方法,但我們首先要先了解一下其他繼承方式**

4. 原型式繼承
//如果o為某個(gè)對(duì)象的prototype,則object返回的 對(duì)象,包含了該對(duì)象原型上的所有方法
function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

Es5 新增的 Object.create() ,類似這樣。 在沒(méi)有必要?jiǎng)?chuàng)建構(gòu)造函數(shù),只想讓一個(gè)對(duì)象與另一個(gè)對(duì)象保持類似的情況下,原型式繼承是完全可以勝任的。不過(guò),包含引用類型值的屬性始終會(huì)共享

5. 寄生式繼承

在復(fù)制新對(duì)象后,繼續(xù)以某種方式增強(qiáng)對(duì)象,即為寄生式繼承。

function createAnother(original) {
    var clone = object(original);
    clone.sayHi = function() {
        doSomeThing();
    };
    return clone;
}

在主要考慮對(duì)象而不是自定義類型和構(gòu)造函數(shù)的時(shí)候,適合使用寄生式繼承

缺點(diǎn): 類似單純的構(gòu)造函數(shù)模式使用,函數(shù)不能復(fù)用

6. 寄生組合式繼承

通過(guò)原型式繼承,繼承父類的原型方法。再通過(guò)構(gòu)造函數(shù)方法,繼承父類的屬性。

function Animal() {
    this.name = "animal";
}
Animal.prototype.getName = function() {
    return this.name;
};

function Cat() {
    Animal.call(this); //借用構(gòu)造函數(shù)
}

//原型繼承方式
function object(superProto) {
    function F() {}
    F.prototype = superProto;
    return new F();
}

Cat.prototype = object(Animal.prototype); //通過(guò)一個(gè)空的函數(shù)作為媒介,將空函數(shù)的原型指向父類型原型,并將子類型的原型指向這個(gè)空函數(shù)的實(shí)例。便只繼承父類原型上的屬性及方法
Cat.prototype.constructor = Cat;
//這里可以之后添加子類的方法
Cat.prototype.run = function() {
    alert("cat run");
};

var cat1 = new Cat();
var cat2 = new Cat();
cat1.name = "changed name";
alert(cat1.getName()); //changed name
alert(cat2.getName()); //animal

最后,寄生組合式繼承是引用類型最理想的繼承范式。
上述代碼還能再進(jìn)一步優(yōu)化。

//原型繼承方式
function object(superProto) {
    function F() {}
    F.prototype = superProto;
    return new F();
}
//公用的繼承方法
function inheritPrototype(subType, superType) {
    subType.prototype = object(superType.prototype);
    subType.prototype.constructor = subType;
}

function Animal() {
    this.name = "animal";
}
Animal.prototype.getName = function() {
    return this.name;
};

function Cat() {
    Animal.call(this); //借用構(gòu)造函數(shù)
}

inheritPrototype(Cat, Animal); //調(diào)用此方法繼承原型

//這里可以之后添加子類的方法
Cat.prototype.run = function() {
    alert("cat run");
};
var cat1 = new Cat();
var cat2 = new Cat();
cat1.name = "changed name";
alert(cat1.getName()); //changed name
alert(cat2.getName()); //animal
小結(jié)

這是 js 對(duì)象的創(chuàng)建以及繼承,es6 中新增了關(guān)鍵字classextend。方便我們進(jìn)行面向?qū)ο蟮木幊獭?/p>

但是理解背后的繼承原理對(duì)我們編程過(guò)程中也是極有幫助的

:)

喜歡就收藏或者點(diǎn)個(gè)贊唄 ?。?/strong>

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

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

相關(guān)文章

  • 前端面試知識(shí)點(diǎn)目錄整理

    摘要:寫在前面金三銀四又到了一年一度的跳槽季相信大家都在準(zhǔn)備自己面試筆記我也針對(duì)自己工作中所掌握或了解的一些東西做了一個(gè)目錄總結(jié)方便自己復(fù)習(xí)詳細(xì)內(nèi)容會(huì)在之后一一對(duì)應(yīng)地補(bǔ)充上去有些在我的個(gè)人主頁(yè)筆記中也有相關(guān)記錄這里暫且放一個(gè)我的面試知識(shí)點(diǎn)目錄大家 寫在前面: 金三銀四, 又到了一年一度的跳槽季, 相信大家都在準(zhǔn)備自己面試筆記, 我也針對(duì)自己工作中所掌握或了解的一些東西做了一個(gè)目錄總結(jié),方便自...

    xzavier 評(píng)論0 收藏0
  • 前端面試知識(shí)點(diǎn)目錄整理

    摘要:寫在前面金三銀四又到了一年一度的跳槽季相信大家都在準(zhǔn)備自己面試筆記我也針對(duì)自己工作中所掌握或了解的一些東西做了一個(gè)目錄總結(jié)方便自己復(fù)習(xí)詳細(xì)內(nèi)容會(huì)在之后一一對(duì)應(yīng)地補(bǔ)充上去有些在我的個(gè)人主頁(yè)筆記中也有相關(guān)記錄這里暫且放一個(gè)我的面試知識(shí)點(diǎn)目錄大家 寫在前面: 金三銀四, 又到了一年一度的跳槽季, 相信大家都在準(zhǔn)備自己面試筆記, 我也針對(duì)自己工作中所掌握或了解的一些東西做了一個(gè)目錄總結(jié),方便自...

    enda 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來(lái)學(xué)習(xí)一門新編程語(yǔ)言吧!

    摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...

    caspar 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來(lái)學(xué)習(xí)一門新編程語(yǔ)言吧!

    摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...

    nihao 評(píng)論0 收藏0
  • SegmentFault 技術(shù)周刊 Vol.40 - 2018,來(lái)學(xué)習(xí)一門新編程語(yǔ)言吧!

    摘要:入門,第一個(gè)這是一門很新的語(yǔ)言,年前后正式公布,算起來(lái)是比較年輕的編程語(yǔ)言了,更重要的是它是面向程序員的函數(shù)式編程語(yǔ)言,它的代碼運(yùn)行在之上。它通過(guò)編輯類工具,帶來(lái)了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語(yǔ)言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺(jué)已經(jīng)到來(lái)了,總結(jié)過(guò)去的 2017,相信小伙們一定有很多收獲...

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

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

0條評(píng)論

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