摘要:于是退而求其次叫為類的構(gòu)造函數(shù)。如果這個(gè)函數(shù)被用在創(chuàng)建自定義對(duì)象的場(chǎng)景中,我們稱這個(gè)函數(shù)為構(gòu)造函數(shù)。遇到的問題始終指向創(chuàng)建當(dāng)前對(duì)象的構(gòu)造函數(shù)。
Object.constructor,prototype
對(duì)象的prototype和constructor是兩個(gè)重要的屬性,他們總是成對(duì)出現(xiàn),提到constructor的地方,不得不涉及到另外一個(gè)非常重要的屬性prototype,它是js中基于原型繼承的一個(gè)基礎(chǔ)。所謂的成對(duì)出現(xiàn),是因?yàn)閒unction的prototype屬性指向了一個(gè)prototype對(duì)象,在prototype對(duì)象中又有一個(gè)constructor屬性,這個(gè)constructor屬性同樣指向一個(gè)constructor對(duì)象,而這個(gè)constructor對(duì)象恰恰就是這個(gè)function函數(shù)本身。
function Person(name) { this.name=name; this.showMe=function() { alert(this.name); } }; var one=new Person("JavaScript"); one.showMe();//JavaScript
很多人見到了久違的new操作符,于是就叫Person為“類”,可是又沒有關(guān)鍵字class的出現(xiàn),覺得叫“類”有點(diǎn)勉強(qiáng)。于是退而求其次叫Person為類的構(gòu)造函數(shù)。這些概念好像都沒有錯(cuò),之所以出現(xiàn)這樣的情況,可能是因?yàn)榇蠹叶紝W(xué)習(xí)了傳統(tǒng)的面向?qū)ο笳Z(yǔ)言(c++,c#,java等),還有一種思維定勢(shì)吧。為了讓javascript也面向?qū)ο螅趈avascript中找到與傳統(tǒng)面向?qū)ο笳Z(yǔ)言的影子。可是按照javascript的說法,function定義的這個(gè)Person就是一個(gè)Object(對(duì)象),而且還是一個(gè)很特殊的對(duì)象,這個(gè)使用function定義的對(duì)象與使用new操作符生成的對(duì)象之間有一個(gè)重要的區(qū)別。
這個(gè)區(qū)別就是function定義的對(duì)象有一個(gè)prototype屬性,使用new生成的對(duì)象就沒有這個(gè)prototype屬性。(這個(gè)之前沒有注意過這個(gè)區(qū)別,代碼測(cè)試下竟然還真是)
function Person(name) { this.name=name; this.showMe=function() { alert(this.name); } }; var one=new Person("js"); alert(one.prototype)//undefined alert(typeof Person.prototype);//object alert(Person.prototype.constructor);//function Person(name) {...};
one這個(gè)對(duì)象竟然沒有prototype屬性。。。
function Person(name) { this.name=name; this.showMe=function() { alert(this.name); } }; Person.prototype.from=function() { alert("I come from prototype."); } var one=new Person("js"); one.showMe();//js,這個(gè)結(jié)果正常 one.from();//I come from prototype.,這個(gè)結(jié)果有一點(diǎn)奇怪
要解釋這個(gè)結(jié)果就要仔細(xì)研究一下new這個(gè)操作符了
var one=new Person("js");
這個(gè)語(yǔ)句執(zhí)行的過程可以分成下面的語(yǔ)句:
var one={}; Person.call(one,"js");
按照《悟透javascript》書中說的,new形式創(chuàng)建對(duì)象的過程實(shí)際上可以分為三步:
第一步是建立一個(gè)新對(duì)象(叫A吧);
第二步將該對(duì)象(A)內(nèi)置的原型對(duì)象設(shè)置為構(gòu)造函數(shù)(就是Person)prototype 屬性引用的那個(gè)原型對(duì)象;
第三步就是將該對(duì)象(A)作為this 參數(shù)調(diào)用構(gòu)造函數(shù)(就是Person),完成成員設(shè)置等初始化工作。
其中第二步中出現(xiàn)了一個(gè)新名詞就是內(nèi)置的原型對(duì)象__prop__,注意這個(gè)新名詞跟prototype對(duì)象不是一回事,__prop__(圖中標(biāo)記的inobj)就指向了函數(shù)Person的prototype對(duì)象。在person的prototype對(duì)象中出現(xiàn)的任何屬性或者函數(shù)都可以在one對(duì)象中直接使用,這個(gè)就是javascript中的原型繼承了。示意圖如下所示:
每個(gè)函數(shù)都有一個(gè)默認(rèn)的prototype屬性。
如果這個(gè)函數(shù)被用在創(chuàng)建自定義對(duì)象的場(chǎng)景中,我們稱這個(gè)函數(shù)為構(gòu)造函數(shù)。 比如下面一個(gè)簡(jiǎn)單的例子:
// 構(gòu)造函數(shù) function Person(name) { this.name = name; } // 定義Person的原型,原型中的屬性可以被自定義對(duì)象引用 Person.prototype = { getName: function() { return this.name; } } var zhang = new Person("ZhangSan"); console.log(zhang.getName()); // "ZhangSan"
作為類比,我們考慮下JavaScript中的數(shù)據(jù)類型 - 字符串(String)、數(shù)字(Number)、數(shù)組(Array)、對(duì)象(Object)、日期(Date)等。
我們有理由相信,在JavaScript內(nèi)部這些類型都是作為構(gòu)造函數(shù)來實(shí)現(xiàn)的;
同時(shí)對(duì)數(shù)組操作的很多方法(比如concat、join、push)應(yīng)該也是在prototype屬性中定義的。
實(shí)際上,JavaScript所有的固有數(shù)據(jù)類型都具有只讀的prototype屬性(因?yàn)槿绻薷牧诉@些類型的prototype屬性,則哪些預(yù)定義的方法就消失了),但是我們可以向其中添加自己的擴(kuò)展方法。
constructor始終指向創(chuàng)建當(dāng)前對(duì)象的構(gòu)造函數(shù)。
var arr = [1, 56, 34, 12];// 等價(jià)于 var foo = new Array(1, 56, 34, 12); console.log(arr.constructor === Array); // true var Foo = function() { }; // 等價(jià)于 var foo = new Function(); console.log(Foo.constructor === Function); // true // 由構(gòu)造函數(shù)實(shí)例化一個(gè)obj對(duì)象 var obj = new Foo(); console.log(obj.constructor === Foo); // true // 將上面兩段代碼合起來,就得到下面的結(jié)論 console.log(obj.constructor.constructor === Function); // true
但是當(dāng)constructor遇到prototype時(shí),有趣的事情就發(fā)生了。 這個(gè)現(xiàn)象在我的這篇博客里基于原型創(chuàng)建對(duì)象的時(shí)候也提到過。鏈接描述
我們知道每個(gè)函數(shù)都有一個(gè)默認(rèn)的屬性prototype,而這個(gè)prototype的constructor默認(rèn)指向這個(gè)函數(shù)。如下例所示:
function Person(name) { this.name = name; }; Person.prototype.getName = function() { return this.name; }; var p = new Person("ZhangSan"); console.log(p.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true // 將上兩行代碼合并就得到如下結(jié)果 console.log(p.constructor.prototype.constructor === Person); // true
當(dāng)時(shí)當(dāng)我們重新定義函數(shù)的prototype時(shí)(這里不是修改而是覆蓋),或者成為原型重寫,constructor的行為就有點(diǎn)奇怪了,如下示例:
function Person(name) { this.name = name; }; Person.prototype = { getName: function() { return this.name; } }; var p = new Person("ZhangSan"); console.log(p.constructor === Person); // false console.log(Person.prototype.constructor === Person); // false console.log(p.constructor.prototype.constructor === Person); // false
是因?yàn)楦采wPerson.prototype時(shí),等價(jià)于進(jìn)行如下代碼操作:
Person.prototype = new Object({ getName: function() { return this.name; } });
而constructor始終指向創(chuàng)建自身的構(gòu)造函數(shù),所以此時(shí)Person.prototype.constructor === Object,即:
function Person(name) { this.name = name; }; Person.prototype = { getName: function() { return this.name; } }; var p = new Person("ZhangSan"); console.log(p.constructor === Object); // true console.log(Person.prototype.constructor === Object); // true console.log(p.constructor.prototype.constructor === Object); // true
如何修正過來,只需要重新覆蓋Person.prototype.constructor即可:
function Person(name) { this.name = name; }; Person.prototype = new Object({ getName: function() { return this.name; } }); Person.prototype.constructor = Person; var p = new Person("ZhangSan"); console.log(p.constructor === Person); // true console.log(Person.prototype.constructor === Person); // true console.log(p.constructor.prototype.constructor === Person); // trueObject的常用方法
javascript中的一切皆對(duì)象,而這些對(duì)象的有一個(gè)最父層的類就是Object,常用的一些屬性方法匯總一下,這些方法在判斷上述問題以及其他方面很有用。
Object.constructor //對(duì)象的構(gòu)造函數(shù) Object.hasOwnProperty() //檢查對(duì)象屬性是否被繼承 Object.isPrototypeOf() //檢查一個(gè)對(duì)象是否是另外一個(gè)對(duì)象的原型 Object.propertyIsEnumerable() //是否可以通過for/in 循環(huán)看到屬性 Object.toLocaleString() //返回對(duì)象的本地字符串表示 Object.toString() //定義一個(gè)對(duì)象的字符串表示 Object.valueOf() //制定對(duì)象的原始值
最近從圖書館把那邊厚厚的《javascript高級(jí)程序設(shè)計(jì)》借過來了,看看單單事件就能將講那么厚厚一章,打算搞一個(gè)基礎(chǔ)知識(shí)系列~~求監(jiān)督和共勉
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86056.html
摘要:給添加屬性給的原型對(duì)象添加屬性原型鏈在中,每個(gè)對(duì)象都有一個(gè)屬性,其保存著的地址就構(gòu)成了對(duì)象的原型鏈。實(shí)例變量實(shí)例函數(shù)原型鏈繼承有了原型鏈,就可以借助原型鏈實(shí)現(xiàn)繼承。是中唯一一個(gè)處理屬性但是不查找原型鏈的函數(shù)。 前端學(xué)習(xí):教程&開發(fā)模塊化/規(guī)范化/工程化/優(yōu)化&工具/調(diào)試&值得關(guān)注的博客/Git&面試-前端資源匯總 歡迎提issues斧正:原型&原型鏈&原型繼承 JavaScript-原...
我們?cè)趯W(xué)習(xí)javascript時(shí),經(jīng)常會(huì)聽到萬物皆對(duì)象,但是呢,其實(shí)萬物皆對(duì)象的對(duì)象也有區(qū)別。分為普通對(duì)象和函數(shù)對(duì)象。1.對(duì)象分為函數(shù)對(duì)象和普通對(duì)象? ??通過new Function()創(chuàng)建的對(duì)象都是函數(shù)對(duì)象,其他的都是普通對(duì)象。showImg(https://segmentfault.com/img/bVbtWre?w=526&h=252); 2.構(gòu)造函數(shù)而提到new關(guān)鍵字,我們不得不提到構(gòu)造...
摘要:然而事實(shí)上并不是。函數(shù)本身也是一個(gè)對(duì)象,但是給這個(gè)對(duì)象添加屬性并不能影響。一圖勝千言作者給出的解決方案,沒有麻煩的,沒有虛偽的,沒有混淆視線的,原型鏈連接不再赤裸裸。所以是這樣的一個(gè)函數(shù)以為構(gòu)造函數(shù),為原型。 注意:本文章是個(gè)人《You Don’t Know JS》的讀書筆記。在看backbone源碼的時(shí)候看到這么一小段,看上去很小,其實(shí)忽略了也沒有太大理解的問題。但是不知道為什么,我...
摘要:基礎(chǔ)原型原型鏈構(gòu)造函數(shù)默認(rèn)有這一行張三李四構(gòu)造函數(shù)擴(kuò)展其實(shí)是的語(yǔ)法糖其實(shí)是的語(yǔ)法糖其實(shí)是使用判斷一個(gè)函數(shù)是否是一個(gè)變量的構(gòu)造函數(shù)原型規(guī)則和示例所有的引用類型數(shù)組對(duì)象函數(shù),都具有對(duì)象屬性即可自有擴(kuò)展的屬性,除外所有的引用類型數(shù)組對(duì)象函數(shù), JavaScript基礎(chǔ) —— 原型&&原型鏈 構(gòu)造函數(shù) function Foo(name, age) { this.name = na...
摘要:而和的存在就是為了建立這種子類與父類間的聯(lián)系。創(chuàng)建一個(gè)基本對(duì)象建立新對(duì)象與原型我把它理解為類之間的連接執(zhí)行構(gòu)造函數(shù)小結(jié)可以理解為類,也就是存儲(chǔ)一類事物的基本信息。原型原型鏈和繼承之間的關(guān)系。 原型 原型的背景 首先,你應(yīng)該知道javascript是一門面向?qū)ο笳Z(yǔ)言。 是對(duì)象,就具有繼承性。 繼承性,就是子類自動(dòng)共享父類的數(shù)據(jù)結(jié)構(gòu)和方法機(jī)制。 而prototype 和 __proto__...
閱讀 1025·2021-09-26 09:55
閱讀 3565·2021-09-24 10:30
閱讀 1368·2021-09-08 09:36
閱讀 2556·2021-09-07 09:58
閱讀 606·2019-08-30 15:56
閱讀 773·2019-08-29 18:32
閱讀 3614·2019-08-29 15:13
閱讀 1844·2019-08-29 13:49