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