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

資訊專欄INFORMATION COLUMN

Javascript中的的對(duì)象——原型模式(Prototype)

岳光 / 2637人閱讀

摘要:使用原型模式添加方法和屬性在前面的章節(jié)中,已經(jīng)學(xué)習(xí)過了如何定義一個(gè)構(gòu)建新對(duì)象時(shí)使用的構(gòu)造函數(shù)。向構(gòu)造函數(shù)的中添加方法和屬性是在對(duì)象被創(chuàng)建的時(shí)候?yàn)閷?duì)象添加功能的另一種方式。讓我們繼續(xù)使用對(duì)象作為構(gòu)造函數(shù)的原型屬性。

本文原文來源:《Object-Oriented JavaScript》By Stoyan Stefanov
本文翻譯來源:赤石俊哉 原創(chuàng)翻譯
版權(quán)申明: 如果您是原文的原作者并且不希望此文被公開,可以聯(lián)系作者刪除。本文翻譯由 赤石俊哉 翻譯整理,您可以用于學(xué)習(xí)交流的目的,但是禁止用于其他用途,因私自濫用引發(fā)的版權(quán)糾紛本人概不負(fù)責(zé)。

原型模式(Prototype)

在這一章節(jié)中你將會(huì)學(xué)習(xí)使用“函數(shù)(function)”對(duì)象中的prototype屬性。在JavaScript的學(xué)習(xí)過程中,理解prototype的工作原理是很重要的一個(gè)部分。畢竟,JavaScript被分類為是一個(gè)基于原型模式對(duì)象模型的語(yǔ)言。其實(shí)原型模式并不難,但是它是一種新的觀念而且往往需要花些時(shí)間去理解。它是JavaScript中的一部分(閉包是另一部分),一旦你“get“了他們,他們就會(huì)變得很容易理解也是很有意義的。在本書的剩余部分中,強(qiáng)烈建議多打多試這些示例。那樣會(huì)更加容易地學(xué)習(xí)和記住這些觀念。
本章中將會(huì)討論以下話題:

每一個(gè)函數(shù)都有一個(gè)prototype屬性,而且它包含了一個(gè)對(duì)象。

向prototype中添加屬性。

使用向prototype中添加的屬性。

函數(shù)自身屬性以及原型屬性的區(qū)別。

每一個(gè)對(duì)象保存在prototype中的私密鏈接——__proto__。

方法:isPrototypeOf(),hasOwnProperty(),propertyIsEnumerable()

如何加強(qiáng)內(nèi)建對(duì)象,比如數(shù)組(array)和字符串(string)。

原型屬性

JavaScript中的函數(shù)是對(duì)象,而且包含了方法和屬性。包括我們常見的一些的方法,像apply()、call()等,常見的屬性,像length、constructor等。還有一個(gè)屬性就是prototype。

當(dāng)你定義了一個(gè)簡(jiǎn)單的函數(shù)foo()之后,你可以像其他對(duì)象一樣,直接訪問這個(gè)函數(shù)的屬性:

>>> function foo(a, b){return a * b;}
>>> foo.length
2

>>> foo.constructor
Function()

prototype這個(gè)屬性在你定義函數(shù)的時(shí)候就創(chuàng)建好了。他的初始值是一個(gè)空對(duì)象。

>>> typeof foo.prototype
"object"

你可以使用屬性和方法來擴(kuò)充這個(gè)空對(duì)象。他們不會(huì)對(duì)foo()函數(shù)本身產(chǎn)生任何影響。他們只會(huì)在當(dāng)你使用foo()作為構(gòu)造函數(shù)的時(shí)候被使用。

使用原型模式添加方法和屬性

在前面的章節(jié)中,已經(jīng)學(xué)習(xí)過了如何定義一個(gè)構(gòu)建新對(duì)象時(shí)使用的構(gòu)造函數(shù)。最主要的思想是在函數(shù)中調(diào)用new時(shí),訪問this變量,它包含了構(gòu)建函數(shù)返回的對(duì)象。擴(kuò)張(添加方法和屬性)this對(duì)象是在對(duì)象被創(chuàng)建時(shí)添加功能的一種方法。
讓我們來看個(gè)例子,Gadget()構(gòu)造方法中使用this來添加兩個(gè)屬性和一個(gè)方法到它創(chuàng)建的對(duì)象里。

function Gadget(name, color){
    this.name = name;
    this.color = color;
    this.whatAreYou = function(){
        return "I am a " + this.color + " " + this.name;
    }
}

向構(gòu)造函數(shù)的prototype中添加方法和屬性是在對(duì)象被創(chuàng)建的時(shí)候?yàn)閷?duì)象添加功能的另一種方式。接下來再添加兩個(gè)屬性pricerating和一個(gè)getInfo()方法。因?yàn)?b>prototype包含一個(gè)對(duì)象,所以你可以像這樣添加:

Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
Gadget.prototype.getInfo = function(){
    return "Rating: " + this.rating + ", Price: " + this.price;
};

你也可以通過另一種方式達(dá)到同樣的目的,就是完全覆蓋掉原型屬性,將它換成你選擇的對(duì)象:

Gadget.prototype = {
    price: 100,
    rating: 3,
    getInfo: function() {
        return `Rating: ` + this.rating + ", Price:" + this.price;
    }
};
使用原型屬性的方法和屬性

你添加到構(gòu)造函數(shù)的原型屬性中的所有方法和屬性你都是可以直接在使用這個(gè)構(gòu)造函數(shù)構(gòu)造新對(duì)象之后,直接使用的。比如,如果你使用Gadget()構(gòu)建函數(shù),創(chuàng)建了一個(gè)newtoy對(duì)象,你可以直接訪問已經(jīng)定義的所有方法和屬性。

>>> var newtoy = new Gadget("webcam", "black");
>>> newtoy.name;
"webcam"

>>> newtoy.color;
"black"

>>> newtoy.whatAreYou();
"I am a black webcam"

>>> newtoy.price;
100

>>> newtoy.rating;
3

>>> newtoy.getInfo();
"Rating:3, Price: 100"

有一點(diǎn)很重要的是,原型屬性是”活的“,在JavaScript中對(duì)象的傳遞是通過引用來進(jìn)行的。為此,原型類型不是直接復(fù)制到新對(duì)象中的。這意味著什么呢?這意味著,我們可以在任何時(shí)間修改任何對(duì)象的原型屬性(甚至你都可以在新建對(duì)象之后進(jìn)行修改),它們都是生效的。
讓我們繼續(xù)來看一個(gè)例子,添加下面的方法到原型屬性里面:

Gadget.prototype.get = function(what){
    return this[what];
};

盡管我們?cè)诙xget()方法之前已經(jīng)生成了newtoy對(duì)象,然而newtoy依舊可以訪問這個(gè)新的方法:

>>> newtoy.get("price");
100

>>> newtoy.get("color");
"black"
“函數(shù)自身屬性”與“原型屬性”的對(duì)比

在上面的getInfo()例子中,使用了this來從內(nèi)部指向?qū)ο蟊旧?,使?b>Gadget.prototype也可以達(dá)到一樣的目的:

Gadget.prototype.getInfo = function(){
    return "Rating: " + Gadget.prototype.rating + ", Price: " + Gadget.prototype.price;
};

這有啥不一樣呢?在回答這個(gè)問題之前,我們先來測(cè)試一下看看原型屬性是怎么工作的吧。
讓我們?cè)倌贸鑫覀兊?b>newtoy對(duì)象:

>>> var newtoy = new Gadget("webcam", "black");

當(dāng)你嘗試訪問newtoy的一個(gè)屬性,使用表達(dá)式newtoy.name,JavaScript引擎將會(huì)瀏覽對(duì)象的所有屬性,尋找一個(gè)叫作name,如果找到它,它的值就會(huì)被返回。

>>> newtoy.name
"webcam"

什么?你想嘗試著訪問rating屬性?JavaScript引擎會(huì)檢查newtoy中的所有屬性,然后沒有找到一個(gè)叫作rating的。然后腳本引擎就會(huì)鑒別出,構(gòu)造函數(shù)中的原型屬性曾經(jīng)嘗試著創(chuàng)建這個(gè)對(duì)象(就像你使用newtoy.constructor.prototype的時(shí)候一樣)。如果屬性在原型屬性中找到了這個(gè)屬性,就會(huì)使用原型屬性中的這個(gè)屬性。

>>> newtoy.rating
3

這和你直接訪問原型屬性一樣。每一個(gè)對(duì)象都有一個(gè)構(gòu)造函數(shù)的屬性,它是對(duì)創(chuàng)建該對(duì)象使用的構(gòu)造函數(shù)的引用。所以,在這個(gè)例子中:

>>> newtoy.constructor
Gadget(name, color)

>>> newtoy.constructor.prototype.rating
3

現(xiàn)在,讓我們?cè)賮砜纯吹谝徊剑恳粋€(gè)對(duì)象都有一個(gè)構(gòu)造函數(shù)。原型屬性是一個(gè)對(duì)象,所以,它也應(yīng)該也有一個(gè)構(gòu)造函數(shù)。進(jìn)而它的構(gòu)造函數(shù)又有一個(gè)原型屬性……

>>> newtoy.constructor.prototype.constructor
Gadget(name, color)
>>> newtoy.constructor.prototype.constructor.prototype
Object price=100 rating=3

這個(gè)循環(huán)將會(huì)持續(xù)下去,具體有多長(zhǎng)取決于這個(gè)原型屬性鏈有多長(zhǎng)。但是最后會(huì)終結(jié)于一個(gè)內(nèi)建的Object()對(duì)象。它是最外層父類。在這個(gè)例子中,如果你嘗試著使用newtoy.toString(),而newtoy他沒有自己的toString()方法,而且它的原型屬性對(duì)象里也沒有,他就會(huì)一直往上找,最后會(huì)調(diào)用Object對(duì)象的toString()方法。

>>> newtoy.toString()
"[object Object]"
使用函數(shù)自身的屬性覆蓋原型屬性的屬性

如上面所演示的,如果你的對(duì)象沒有一個(gè)確切的自己的屬性,可以使用一個(gè)原型鏈上層的對(duì)象。如果對(duì)象和原型屬性里面有相同名字的屬性,自身的屬性會(huì)被優(yōu)先使用。
接下來我們來模擬一個(gè)屬性同時(shí)存在于自身屬性和原型屬性中:

function Gadget(name){
    this.name = name;
}

>>> Gadget.prototype.name = "foo";
"foo"

創(chuàng)建一個(gè)新對(duì)象,訪問它的name屬性,它會(huì)給你對(duì)象自身的name屬性。

>>> var toy = new Gadget("camera");
>>> toy.name;
"camera"

如果你刪除這個(gè)屬性,那么原型屬性中使用相同名字的屬性就會(huì)“表現(xiàn)出來”:

>>> delete toy.name;
true

>>> toy.name;
"foo"

當(dāng)然,你可以重新創(chuàng)建它的自身屬性:

>>> toy.name = "camera";
>>> toy.name;
"camera"
遍歷屬性

如果你希望列出一個(gè)對(duì)象的所有屬性,你可以使用一個(gè)for-in循環(huán)。在第二章節(jié)中,學(xué)習(xí)了如何遍歷一個(gè)數(shù)組里面的所有元素:

var a = [1, 2, 3];
for (var i in a)
{
    console.log(a[i]);
}

數(shù)組是一個(gè)對(duì)象,所以可以推導(dǎo)出for-in遍歷對(duì)象的時(shí)候:

var o = {p1: 1, p2: 2};
for (var i in o) {
    console.log(i + "=" + o[i]);
}

這將會(huì)產(chǎn)生:

p1=1
p2=2

需要知道的幾個(gè)細(xì)節(jié):

不是所有的屬性都在for-in循環(huán)中顯示出來。比如,數(shù)組的length,以及constructor屬性就不會(huì)被顯示出來。被顯示出來的屬性叫做可枚舉的。你可以使用每個(gè)對(duì)象都能提供的propertyIsEnumerable()方法來檢查一個(gè)屬性是不是可枚舉的。

原型鏈中原型屬性如果是可枚舉的,也會(huì)被顯示出來。你可以使用hasOwnProperty()方法來檢查一個(gè)屬性是自身屬性還是原型屬性。

propertyIsEnumerable()將會(huì)對(duì)所有原型屬性中的屬性返回false,盡管他們會(huì)在for-in循環(huán)中顯示出來,也是可枚舉的。

為了看看這些函數(shù)的效果,我們使用一個(gè)簡(jiǎn)化版本的Gadget()

function Gadget(name, color)
{
    this.name = name;
    this.color = color;
    this.someMethod = function(){
        return 1;
    }
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;

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

var newtoy = new Gadget("webcam", "black");

如果你使用for-in循環(huán),你可以看到對(duì)象的所有屬性,包括那些原型屬性的:

for (var prop in newtoy){
    console.log(prop + " = " + newtoy[prop];
}

這個(gè)結(jié)果也包含對(duì)象的方法(那是因?yàn)榉椒ㄊ钦妙愋褪呛瘮?shù)的屬性):

name = webcam
color = black
someMethod = function(){ return 1;}
price = 100
rating = 3

如果你想?yún)^(qū)分對(duì)象自身屬性和原型屬性的屬性,使用hasOwnProperty(),試試這個(gè):

>>> newtoy.hasOwnProperty("name")
true

>>> newtoy.hasOwnProperty("price")
false

讓我們?cè)賮硌h(huán)一次,但是這次只顯示自身的屬性:

for (var prop in newtoy){
    if (newtoy.hasOwnProperty(prop)){
        console.log(prop + "=" + newtoy[prop]);
    }
}

結(jié)果:

name=webcam
color=black
someMethod=function(){return 1;}

接下來讓我們?cè)囋?b>propertyIsEnumerable()。如果自身屬性不是內(nèi)置的屬性,這個(gè)函數(shù)就會(huì)返回true:

>>> newtoy.propertyIsEnumerable("name")
true

>>> newtoy.propertyIsEnumerable("constructor")
false

任何從原型鏈上來的屬性都是不可枚舉的:

>>> newtoy.propertyIsEnumerable("price")
false

注意,雖然如果你獲取了包含在原型屬性中對(duì)象,并且調(diào)用了它的propertyIsEnumerable(),這個(gè)屬性是可以枚舉的。

>>> newtoy.constructor.prototype.propertyIsEnumberable("price")
true
isPrototypeOf()

每一個(gè)對(duì)象都有isPrototypeOf()方法。這個(gè)方法會(huì)告訴你指定的對(duì)象是誰(shuí)的原型屬性。
我們先寫一個(gè)簡(jiǎn)單的對(duì)象monkey

var monkey = {
    hair: true,
    feeds: "bananas",
    breathes: "air"
};

接下來,讓我們建立一個(gè)Human()構(gòu)造函數(shù),然后設(shè)定它的prototype屬性指向monkey。

function Human(name){
    this.name = name;
}
Human.prototype = monkey;

如果你創(chuàng)建一個(gè)叫作georgeHuman對(duì)象,然后問它:“monkeygeorge的原型屬性嗎?”,你就會(huì)得到true。

>>> var george = new Human("George");
>>> monkey.isPrototypeOf(george)
true
秘密的__proto__鏈接

如你所知的,當(dāng)你嘗試訪問一個(gè)不存在與當(dāng)前對(duì)象的屬性時(shí),它會(huì)查詢?cè)蛯傩缘膶傩浴?br>讓我們繼續(xù)使用monkey對(duì)象作為Human()構(gòu)造函數(shù)的原型屬性。

var monkey = {
    feeds: "bananas",
    breathes: "air"
};
function Human() {}
Human.prototype = monkey;

接下來創(chuàng)建一個(gè)developer對(duì)象,然后給他一些屬性:

var developer = new Human();
developer.feeds = "pizza";
developer.hacks = "JavaScript";

現(xiàn)在,我們來做些查詢吧。hacksdeveloper的屬性:

>>> developer.hacks
"JavaScript"

feeds可以在對(duì)象中被找到:

>>> developer.feeds
"pizza"

breathes不存在于developer對(duì)象中,由于有一個(gè)秘密的鏈接指向原型類型對(duì)象,所以轉(zhuǎn)而查找原型類型。

>>> developer.breathes
"air"

可以從developer對(duì)象中得到原型屬性對(duì)象呢?當(dāng)然,可以啦。使用constructor作為中間對(duì)象,就像developer.constructor.prototype指向monkey一樣。但是這并不是十分可靠的。因?yàn)?b>constructor大多時(shí)候用于提供信息的用途,而且是可以隨時(shí)被覆蓋修改的。你甚至可以用一個(gè)不是對(duì)象的東西覆蓋掉它。這樣做絲毫不會(huì)影響到原型鏈的功能。

讓我們看一些字符串的構(gòu)造屬性:

>>> developer.constructor = "junk"
"junk"

看上去,prototype已經(jīng)亂成一團(tuán)了:

>>> typeof developer.constructor.prototype
"undefined"

但是事實(shí)卻并非如此,因?yàn)殚_發(fā)者仍然呼吸著“空氣”(developerbreathes屬性仍然是air):

>>> developer.breathes
"air"

這表示原型屬性的秘密鏈接仍然存在。在火狐瀏覽器中公開的這個(gè)秘密鏈接是__proto__屬性(proto前后各加兩個(gè)下劃線)。

>>> developer._proto__
Object feeds = bananas breathes=air

你可以在學(xué)習(xí)的過程中使用這個(gè)秘密鏈接,但是實(shí)際編碼中不推薦使用。因?yàn)樗淮嬖谟贗nternet Explorer中,所以你的代碼將會(huì)變得難以移植。打個(gè)比方,如果你使用monkey創(chuàng)建了一堆對(duì)象,而且你現(xiàn)在想在所有的對(duì)象中更改一些東西。你可以修改monkey,而且所有的實(shí)例都會(huì)繼承這些變化。

>>> monkey.test = 1
1

>>> developer.test
1

__proto__不是等效于prototype。__proto__是實(shí)例的一個(gè)屬性,盡管prototype是構(gòu)造函數(shù)的一個(gè)屬性。

>>> typeof developer.__proto__
"object"

>>> typeof developer.prototype
"undefined"

再次強(qiáng)調(diào),你可以在Debug或者是學(xué)習(xí)的時(shí)候使用__proto__,其他時(shí)候不要。

擴(kuò)充內(nèi)建對(duì)象

內(nèi)建的一些對(duì)象像構(gòu)造函數(shù)Array,String,甚至是ObjectFunction()都可以通過他們的原型屬性來進(jìn)行擴(kuò)充。打個(gè)比方,你就可以向Array原型屬性中添加新方法,而且它們可以在所有的數(shù)組中被使用。讓我們來試試。
在PHP中,有一個(gè)函數(shù)叫做in_array(),它會(huì)告訴你如果數(shù)組中是否存在某個(gè)值。在JavaScript中,沒有inArray()這樣的函數(shù),所以我們可以實(shí)現(xiàn)它,并添加到Array.prototype中。

Array.prototype.inArray = function(needle) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i] === needle) {
            return true;
        }
    }   
    return false; 
}

現(xiàn)在,所有的數(shù)組就都有新的方法了。讓我試試:

>>> var a = ["red", "green", "blue"]; 
>>> a.inArray("red");
true

>>> a.inArray("yellow");
false

真是簡(jiǎn)單快捷!讓我再來做一個(gè)。想象一下你的程序可能經(jīng)常需要反轉(zhuǎn)字符串吧,或許你會(huì)認(rèn)為字符串對(duì)象應(yīng)該有一個(gè)內(nèi)建的reverse()方法,畢竟數(shù)組有reverse()方法。你可以輕松地添加reverse()方法給String的原型屬性。瀏覽Array.prototype.reverse()(這和第四章末尾的練習(xí)相似)。

String.prototype.reverse = function() {
    return Array.prototype.reverse.apply(this.split("")).join("");
}

這個(gè)代碼使用split()使用字符串生成了一個(gè)數(shù)組,然后調(diào)用了這個(gè)數(shù)組上的reverse()方法,生成了一個(gè)反轉(zhuǎn)的數(shù)組。然后再使用join()將反轉(zhuǎn)的數(shù)組變回了字符串。讓我們?cè)囋囆碌姆椒ǎ?/p>

>>> "Stoyan".reverse();
"nayotS"
擴(kuò)充內(nèi)建對(duì)象——討論

通過原型屬性來擴(kuò)充內(nèi)建對(duì)象是一項(xiàng)強(qiáng)力的技術(shù),而且你可以用它來將JavaScript塑造成你想要的樣子。你在使用這種強(qiáng)有力的方法之前都要徹底地思考清楚你的想法。
看看一個(gè)叫做Prototype的JavaScript庫(kù),它的作者太愛這個(gè)方法了,以至于連庫(kù)的名字都叫這個(gè)了。使用這個(gè)庫(kù),你可以使用一些JavaScript方法,讓使用JavaScript如Ruby語(yǔ)言一樣靈活。
YUI(雅虎用戶界面)庫(kù)是另一個(gè)比較流行的JavaScript庫(kù)。它的作者則是明確地反對(duì)這個(gè)領(lǐng)域。他們不會(huì)以任何方式更改內(nèi)建對(duì)象。不管你用的是什么庫(kù),修改核心對(duì)象都只會(huì)迷惑庫(kù)的使用者,而且造成意料之外的錯(cuò)誤。
事實(shí)是,JavaScript發(fā)生了變化,瀏覽器也帶來了支持更多功能的新版本?,F(xiàn)在你認(rèn)為需要擴(kuò)充到原型屬性的缺失的功能,也許在明天就變成了內(nèi)建的方法。因此你的方法可能就不被需要了。但是如果你使用這種方法已經(jīng)寫了很多代碼而且你的方法又有些不同于內(nèi)建的新內(nèi)建實(shí)現(xiàn)呢?
最起碼來說你能做的是,在實(shí)現(xiàn)一個(gè)方法之前先去檢查一下它是否存在。我們的上一個(gè)例子就應(yīng)該像這樣:

if (!String.prototype.reverse) {
  String.prototype.reverse = function() {   
    return Array.prototype.reverse.apply(this.split("")).join(""); 
  } 
}
一些原型屬性的陷阱

在處理原型屬性的時(shí)候,這兩個(gè)現(xiàn)象是需要考慮在內(nèi)的:

prototype.constructor是不可靠的。

創(chuàng)建一個(gè)簡(jiǎn)單的構(gòu)建函數(shù)和兩個(gè)對(duì)象:

>>> function Dog(){ this.tail = true; }
>>> var benji = new Dog();
>>> var rusty = new Dog();

甚至在創(chuàng)建了對(duì)象之后,你仍可以向原型屬性添加屬性,而且對(duì)象會(huì)使用新的屬性。讓我們插進(jìn)方法say()

>>> Dog.prototype.say = function(){ return "Woof!";}

兩個(gè)對(duì)象都會(huì)使用新的方法:

>>> benji.say();
"Woof!"

>>> rusty.say();
"Woof!"

到此為止,如果你詢問你的對(duì)象,用來創(chuàng)建他們的構(gòu)建函數(shù)是什么,他們還會(huì)正確地匯報(bào):

>>> benji.constructor;
Dog();

>>> rusty.constructor;
Dog();

一個(gè)有趣的現(xiàn)象是如果你問原型屬性的構(gòu)造函數(shù)是什么,你仍然會(huì)得到Dog(),他不算太準(zhǔn)確。原型屬性是Object()創(chuàng)建的一個(gè)普通對(duì)象而已。使用Dog()構(gòu)造的不含任何屬性的對(duì)象。

>>> benji.constructor.prototype.constructor
Dog()

>>> typeof benji.constructor.prototype.tail
"undefined"

現(xiàn)在我們用一個(gè)全新的對(duì)象完全覆蓋原型屬性對(duì)象:

>>> Dog.prototype = {paws: 4, hair: true};

這證明我們的舊對(duì)象不能訪問新原型屬性的屬性。他們?nèi)员3种c舊原型屬性對(duì)象的秘密鏈接。

>>> typeof benji.paws
"undefined"

>>> benji.say()
"Woof!"

>>> typeof benji.__proto__.say
"function"

>>> typeof benji.__proto__.paws
"undefined"

你再創(chuàng)建新的對(duì)象,將會(huì)使用更新后的原型屬性:

>>> var lucy = new Dog();
>>> lucy.say()
TypeError: lucy.say is not a function

>>> lucy.paws
4

指向新原型屬性的私密鏈接__proto__

>>> typeof lucy.__proto__.say
"undefined"

>>> typeof lucy.__proto__.paws
"number"

新對(duì)象的構(gòu)建函數(shù)屬性不再被正確地匯報(bào)出來了。本來應(yīng)該指向Dog(),但是卻指向了Object()

>>> lucy.constructor
Object()
>>> benji.constructor
Dog()

最難區(qū)分的部分是當(dāng)你查找構(gòu)造函數(shù)的原型屬性時(shí):

>>> typeof lucy.constructor.prototype.paws
"undefined"
>>> typeof benji.constructor.prototype.paws
"number"

下面的語(yǔ)句將會(huì)修復(fù)上面所有的意料之外的現(xiàn)象:

>>> Dog.prototype = {paws: 4, hair: true};
>>> Dog.prototype.constructor = Dog;

當(dāng)你覆蓋原型屬性,推薦重置constructor屬性。

總結(jié)

讓我們來總結(jié)一下這一章節(jié)中學(xué)習(xí)的幾個(gè)要點(diǎn)。

所有的函數(shù)都有一個(gè)叫作prototype的屬性,初始情況下,它包含一個(gè)空白的對(duì)象。

你可以向原型屬性中添加屬性和方法。你甚至可以將它完全替換成你選擇的對(duì)象。

當(dāng)你使用構(gòu)造函數(shù)穿件對(duì)象(使用new),這個(gè)對(duì)象會(huì)有一個(gè)秘密鏈接指向它的原型屬性,而且可以把原型屬性的屬性當(dāng)成自己的來用。

相比原型屬性的屬性,同名自身的屬性擁有更高的優(yōu)先級(jí)。

使用hasOwnProperty()方法來區(qū)分自身屬性和原型屬性的屬性。

存在一個(gè)原型鏈:如果你的對(duì)象foo沒有屬性bar,當(dāng)你使用foo.bar的時(shí)候,JavaScript會(huì)從它的原型屬性中去尋找bar屬性。如果沒有找到,它會(huì)繼續(xù)在原型屬性的原型屬性中找,然后是原型屬性的原型屬性的原型屬性,而且一步一步向上,直到最高層父類Object。

你可以擴(kuò)充內(nèi)建構(gòu)造函數(shù)。所有的對(duì)象都可以應(yīng)用你的擴(kuò)充。申明Array.prototype.flip,而后所有的數(shù)組都會(huì)馬上擁有一個(gè)flip()方法。[1,2,3].flip()。在擴(kuò)充方法和屬性之前,檢查是否存在,為你的代碼添加未來的保證。

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

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

相關(guān)文章

  • js對(duì)象詳解(JavaScript對(duì)象深度剖析,深度理解js對(duì)象)

    摘要:對(duì)象詳解對(duì)象深度剖析,深度理解對(duì)象這算是醞釀很久的一篇文章了。用空構(gòu)造函數(shù)設(shè)置類名每個(gè)對(duì)象都共享相同屬性每個(gè)對(duì)象共享一個(gè)方法版本,省內(nèi)存。 js對(duì)象詳解(JavaScript對(duì)象深度剖析,深度理解js對(duì)象) 這算是醞釀很久的一篇文章了。 JavaScript作為一個(gè)基于對(duì)象(沒有類的概念)的語(yǔ)言,從入門到精通到放棄一直會(huì)被對(duì)象這個(gè)問題圍繞。 平時(shí)發(fā)的文章基本都是開發(fā)中遇到的問題和對(duì)...

    CatalpaFlat 評(píng)論0 收藏0
  • JavaScript七種非常經(jīng)典的創(chuàng)建對(duì)象方式

    摘要:創(chuàng)建對(duì)象的方式有很多,通過構(gòu)造函數(shù)或?qū)ο笞置媪康姆绞揭部梢詣?chuàng)建單個(gè)對(duì)象,顯然這兩種方式會(huì)產(chǎn)生大量的重復(fù)代碼,并不適合量產(chǎn)。四組合使用構(gòu)造函數(shù)模式和原型模式組合使用構(gòu)造函數(shù)模式和原型模式是使用最為廣泛認(rèn)同度最高的一種創(chuàng)建自定義類型的方法。 JavaScript創(chuàng)建對(duì)象的方式有很多,通過Object構(gòu)造函數(shù)或?qū)ο笞置媪康姆绞揭部梢詣?chuàng)建單個(gè)對(duì)象,顯然這兩種方式會(huì)產(chǎn)生大量的重復(fù)代碼,并不適合量...

    ARGUS 評(píng)論0 收藏0
  • JS對(duì)象(1)重新認(rèn)識(shí)面向對(duì)象

    摘要:對(duì)象重新認(rèn)識(shí)面向?qū)ο竺嫦驅(qū)ο髲脑O(shè)計(jì)模式上看,對(duì)象是計(jì)算機(jī)抽象現(xiàn)實(shí)世界的一種方式。除了字面式聲明方式之外,允許通過構(gòu)造器創(chuàng)建對(duì)象。每個(gè)構(gòu)造器實(shí)際上是一個(gè)函數(shù)對(duì)象該函數(shù)對(duì)象含有一個(gè)屬性用于實(shí)現(xiàn)基于原型的繼承和共享屬性。 title: JS對(duì)象(1)重新認(rèn)識(shí)面向?qū)ο? date: 2016-10-05 tags: JavaScript 0x00 面向?qū)ο?從設(shè)計(jì)模式上看,對(duì)象是...

    superw 評(píng)論0 收藏0
  • 復(fù)習(xí)Javascript專題(三):面向對(duì)象對(duì)象的創(chuàng)建與繼承,原型原型鏈)

    摘要:在創(chuàng)建子類實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。構(gòu)造函數(shù)繼承子類傳進(jìn)的值是基本思想是在子類構(gòu)造函數(shù)的內(nèi)部調(diào)用超類或父類型構(gòu)造函數(shù)。繼承保證構(gòu)造函數(shù)指針指向如果想同時(shí)繼承多個(gè),還可使用添加屬性的方式類繼承, OOP:Object Oriented Programming 面向?qū)ο缶幊獭?題外話:面向?qū)ο蟮姆秶鷮?shí)在太大,先把這些大的東西理解理解。 1.什么是對(duì)象? 根據(jù)高程和權(quán)威指南上...

    testHs 評(píng)論0 收藏0
  • 面向對(duì)象JavaScript(如何一步步成為js高手)

    摘要:雖然,也是面向疾苦的語(yǔ)言,但是,它和靜態(tài)類型語(yǔ)言的面向接口編程不一而足。對(duì)象對(duì)他自己的行為負(fù)責(zé),其他對(duì)象不關(guān)心它的內(nèi)部實(shí)現(xiàn)。 ‘工欲善其事,必先利其器’,在深入學(xué)習(xí)JavaScript之前,我認(rèn)為我們很有必要了解以下,JavaScript這門面向?qū)ο蟮膭?dòng)態(tài)語(yǔ)言到底是一門什么樣的語(yǔ)言。 JavaScript vs 其他面向?qū)ο笳Z(yǔ)言 它沒有使用像Java等傳統(tǒng)的面向?qū)ο笳Z(yǔ)言的類式繼承,而...

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

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

0條評(píng)論

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