摘要:中創(chuàng)建對(duì)象是如何實(shí)現(xiàn)的其實(shí)通過(guò)上面方式,使用構(gòu)造函數(shù)聲明實(shí)例的專(zhuān)屬變量和方法,使用原型聲明公用的實(shí)例和方法,已經(jīng)是創(chuàng)建對(duì)象的完美解決方案了。
var cat = { name: "tom", info: this.name + ": 1212", getName: function() { return this.name; } };
注意上例屬性info中,使用了this.name,這里的this指向window對(duì)象,請(qǐng)盡量避免在定義對(duì)象屬性時(shí)使用表達(dá)式,而將有表達(dá)式的內(nèi)容寫(xiě)入到函數(shù)中。
var dog = new Object(); dog.name = "tim"; dog.getName = function() { return dog.name; }
可以使用delete刪除對(duì)象的屬性和方法
delete dog.name;
在window作用域中,不能使用delete刪除var, function定義的屬性和方法,可以刪除沒(méi)有使用var, function定義的屬性和方法
在實(shí)際使用當(dāng)中,字面量創(chuàng)建對(duì)象雖然很有用,但是它并不能滿足我們的所有需求,我們希望能夠能夠和其他后臺(tái)語(yǔ)言一樣創(chuàng)建一個(gè)類(lèi),然后聲明類(lèi)的實(shí)例就能夠多次使用,而不用每次使用的時(shí)候都要重新創(chuàng)建它,于是,便有了工廠模式的出現(xiàn)。
function person(name) { var o = new Object(); o.name = name; o.getName = function() { return this.name; } return o; } var person1 = person("rose"); var person2 = person("jake");
這種模式在函數(shù)的內(nèi)部創(chuàng)建了一個(gè)空對(duì)象,然后逐一添加屬性和方法,最后返回,實(shí)現(xiàn)了對(duì)象得以復(fù)用的目的。但是存在2個(gè)很大的問(wèn)題
無(wú)法識(shí)別對(duì)象的類(lèi)型
console.log(person1 instanceof person); // false
每個(gè)對(duì)象調(diào)用的同名方法其實(shí)并不同一個(gè)方法
console.log(person1.getName == person2.getName); // false
其實(shí)就相當(dāng)于每次聲明對(duì)象都被重新創(chuàng)建,只不過(guò)寫(xiě)法上簡(jiǎn)單了一點(diǎn)而已。
var Person = function(name) { this.name = name; this.getName = function() { return this.name; } } var person1 = new Person("tom"); var person2 = new Person("tim");
使用var或者function聲明函數(shù)都可以,只是我寫(xiě)例子的時(shí)候想到什么就寫(xiě)了什么,這個(gè)區(qū)別在這里不是重點(diǎn)
和工廠模式相比,自定義構(gòu)造函數(shù)沒(méi)有在函數(shù)內(nèi)部顯示的創(chuàng)建和返回對(duì)象,而是使用this,當(dāng)然,看上去簡(jiǎn)潔了許多,那么它解決了工廠模式的什么問(wèn)題呢?
console.log(person1 instanceof Person); // ture console.log(person1.getName == person2.getName); //false
從上面代碼可以看出,對(duì)象的類(lèi)別可以判斷了,person1就是Person的對(duì)象,可是2個(gè)同名方法任然不是同一個(gè)方法,而是重新創(chuàng)建,其實(shí)構(gòu)造函數(shù)內(nèi)部的實(shí)現(xiàn),可以將上面的代碼寫(xiě)成這樣來(lái)理解
var Person = function(name) { var this = {}; this.name = name; this.getName = function() { return this.name; } return this; }
看上去和工廠模式就有點(diǎn)像,只是this的聲明和返回都是隱式的。下一步,我們將要介紹關(guān)鍵先生,原型
原型并沒(méi)有那么神秘,因?yàn)樵趈avascript中,它無(wú)處不在。為了了解原型,我們可以在chrome瀏覽器的console中,隨意創(chuàng)建一個(gè)函數(shù)
function a(){}
然后繼續(xù)輸入
a.prototype
得到的結(jié)果如下
a { constructor: function a(), _proto_: Object }
沒(méi)錯(cuò),得到的這個(gè)a,就是關(guān)鍵先生原型了。每一個(gè)函數(shù)都有一個(gè)prototype屬性,他就像一個(gè)指針一樣指向它的原型,而每一個(gè)原型,都有一個(gè)constructor屬性,指向他的構(gòu)造函數(shù)。
那么原型在創(chuàng)建對(duì)象中有什么用呢?
一個(gè)例子,千錘百煉,如下
function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; } var person1 = new Person("rose"); var person2 = new Person("Jake");
在這里,我們將屬性寫(xiě)在了構(gòu)造函數(shù)里,將令人頭疼的方法寫(xiě)在原型里,看看上面的問(wèn)題得到解決沒(méi)有
console.log(person1 instanceof Person); // true console.log(person1.getName === person2.getName); // true
OK,問(wèn)題完美解決。
當(dāng)然也可以將屬性寫(xiě)入原型中,但是如果那樣的話,屬性就會(huì)如同方法一樣被公用了,因此一般來(lái)說(shuō),屬性會(huì)寫(xiě)入構(gòu)造函數(shù)之中,方法寫(xiě)入原型之中。當(dāng)然,這視情況而定。
如果你想進(jìn)一步了解原型,可以看下圖。
當(dāng)我們使用new Person時(shí)便會(huì)創(chuàng)建一個(gè)實(shí)例,比如這里的person1與person2,這里的實(shí)例中,會(huì)有一個(gè)_proto_屬性指向原型。
原型中的查找機(jī)制
當(dāng)我們使用實(shí)例person1調(diào)用方法person.getName()時(shí),我們首先找的,是看看構(gòu)造函數(shù)里面有沒(méi)有這個(gè)方法,如果構(gòu)造函數(shù)中存在,就直接調(diào)用構(gòu)造函數(shù)的方法,如果構(gòu)造函數(shù)不存在,才回去查找原型中是否存在該方法
function Cat(name) { this.name = name; this.age = 12; this.getName = function() { return "constructor"; } } Cat.prototype.name = "proto name"; Cat.prototype.getName = function() { return this.name; } var tim = new Cat("Tim"); console.log(tim.name); // tim console.log(tim.getName()); // constructor
可以看到上例中,當(dāng)原型和構(gòu)造函數(shù)中擁有同樣的方法和屬性的時(shí)候,構(gòu)造函數(shù)中的被執(zhí)行。
于是,這里便會(huì)有一個(gè)十分重要的概念需要理解,那就是this的指向問(wèn)題。
在整個(gè)創(chuàng)建對(duì)象的過(guò)程當(dāng)中,this到底指向誰(shuí)?
function Person(name) { this.name = name; // this.getName = function() { // return "constructor"; // } } Person.prototype.getName = function() { return this.name; } Person.prototype.showName = function() { return this.getName(); } var rose = new Person("rose"); console.log(rose.showName()); //rose
其實(shí)在new執(zhí)行時(shí),構(gòu)造函數(shù)中的this與原型中的this都被強(qiáng)行指向了new創(chuàng)建的實(shí)例對(duì)象。
如果需要寫(xiě)在原型上的方法很多的話,還可以這樣來(lái)寫(xiě),讓寫(xiě)法看上去更加簡(jiǎn)潔
Person.prototype = { constructor: Person, getName: function(){}, showName: function(){}, ... }
constructor:Person這一句必不可少,因?yàn)?b>{}也是一個(gè)對(duì)象,當(dāng)使用Person.prototype = {}時(shí),相當(dāng)于重新定義了prototype的指向,因此手動(dòng)修正{}的constructor屬性,讓他成為Person的原型。
其實(shí)通過(guò)上面方式,使用構(gòu)造函數(shù)聲明實(shí)例的專(zhuān)屬變量和方法,使用原型聲明公用的實(shí)例和方法,已經(jīng)是創(chuàng)建對(duì)象的完美解決方案了。可是唯一的不足在于,每次創(chuàng)建實(shí)例都要使用new來(lái)聲明。這樣未免太過(guò)麻煩,如果jquery對(duì)象也這樣創(chuàng)建,那么你就會(huì)看到一段代碼中有無(wú)數(shù)個(gè)new,可是jQuery僅僅只是使用了$("xxxx")便完成了實(shí)例的創(chuàng)建,這是如何做到的呢?
還是按照慣例,先貼代碼。
(function(window, undefined) { var Person = function(name) { return new Person.fn.init(name); } Person.prototype = Person.fn = { constructor: Person, init: function(name) { this.name = name; return this; }, getName: function() { return this.name; } } Person.fn.init.prototype = Person.fn; window.Person = window.$ = Person; })(window); console.log($("tom").getName());
一步一步來(lái)分析
首先為了避免變量污染,使用了函數(shù)自執(zhí)行的方式。這種方式讓javascript代碼具備了模塊的特性,因此大多數(shù)js庫(kù)都會(huì)這樣做
(function(){ ... })()
傳入window參數(shù),是為了讓jquery對(duì)象在外window中可以被訪問(wèn),因此有如下一句代碼
window.Person = window.$ = Person;
這樣我們就可以直接使用$來(lái)調(diào)用Person構(gòu)造函數(shù)
關(guān)鍵問(wèn)題在于,真正的構(gòu)造函數(shù)并不是Person,而是Person原型中的init方法。其中的復(fù)雜關(guān)系,我們借助下圖來(lái)分析了解,表達(dá)能力實(shí)在有限,也不知道如何才能表達(dá)的更加簡(jiǎn)潔易懂。
當(dāng)外部調(diào)用$().getName()時(shí),函數(shù)內(nèi)部的執(zhí)行順序如下
new Person.fn.init() // 而init的原型,通過(guò)下面一句指向了Person的原型 Person.fn.init.prototype = Person.fn; // 于是就可以調(diào)用原型中的getName方法了
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/86189.html
摘要:字面量方式這是最簡(jiǎn)單最基本的一種方法。簡(jiǎn)單的構(gòu)造函數(shù)方式通過(guò)這樣的形式創(chuàng)建對(duì)象。結(jié)合上面的簡(jiǎn)單構(gòu)造函數(shù)和原型,一個(gè)完整的構(gòu)造函數(shù)應(yīng)該是這樣的還有一種方法就是提供的簡(jiǎn)單實(shí)現(xiàn)下中的,,創(chuàng)建一個(gè)對(duì)象談?wù)剬?duì)象的理解。避免使用表達(dá)式又稱動(dòng)態(tài)屬性。 要點(diǎn):數(shù)據(jù)類(lèi)型、面向?qū)ο蟆⒗^承、閉包、插件、作用域、跨域、原型鏈、模塊化、自定義事件、異步裝載回調(diào)、模板引擎、Nodejs等。 JS基本類(lèi)型有什么?引...
摘要:接下來(lái)該填表了生成行和單元格為了填充表格可以遵循同樣的方法,但這次我們需要迭代數(shù)組中的每個(gè)對(duì)象。對(duì)于每個(gè)對(duì)象,我們可以使用生成單元格。 翻譯:瘋狂的技術(shù)宅原文:https://www.valentinog.com/bl... 本文首發(fā)微信公眾號(hào):jingchengyideng歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章 怎樣用原生 JavaScript 生成表格需?本文告訴你答案!...
摘要:在中函數(shù)是一等對(duì)象,它們不被聲明為任何東西的一部分,而所引用的對(duì)象稱為函數(shù)上下文并不是由聲明函數(shù)的方式?jīng)Q定的,而是由調(diào)用函數(shù)的方式?jīng)Q定的。更為準(zhǔn)確的表述應(yīng)該為當(dāng)對(duì)象充當(dāng)函數(shù)的調(diào)用函數(shù)上下文時(shí),函數(shù)就充當(dāng)了對(duì)象的方法。 引言:當(dāng)理解了對(duì)象和函數(shù)的基本概念,你可能會(huì)發(fā)現(xiàn),在JavaScript中有很多原以為理所當(dāng)然(或盲目接受)的事情開(kāi)始變得更有意義了。 1.JavaScript...
摘要:點(diǎn)擊直達(dá)前文譯一個(gè)小時(shí)搭建一個(gè)全棧應(yīng)用框架上如果沒(méi)有,但還是要繼續(xù)學(xué)習(xí)本教程,可以到我的頁(yè)面下載代碼。從服務(wù)器返回隨機(jī)語(yǔ)言的每當(dāng)我們與服務(wù)器上的端點(diǎn)進(jìn)行通話時(shí),為了能夠請(qǐng)求一個(gè)隨機(jī)的歐洲語(yǔ)言,必須更改文件中的功能。 翻譯:瘋狂的技術(shù)宅原文標(biāo)題:Creating a full-stack web application with Python, NPM, Webpack and Reac...
摘要:點(diǎn)擊直達(dá)前文譯一個(gè)小時(shí)搭建一個(gè)全棧應(yīng)用框架上如果沒(méi)有,但還是要繼續(xù)學(xué)習(xí)本教程,可以到我的頁(yè)面下載代碼。從服務(wù)器返回隨機(jī)語(yǔ)言的每當(dāng)我們與服務(wù)器上的端點(diǎn)進(jìn)行通話時(shí),為了能夠請(qǐng)求一個(gè)隨機(jī)的歐洲語(yǔ)言,必須更改文件中的功能。 翻譯:瘋狂的技術(shù)宅原文標(biāo)題:Creating a full-stack web application with Python, NPM, Webpack and Reac...
閱讀 2129·2021-09-29 09:35
閱讀 2012·2019-08-30 14:15
閱讀 3028·2019-08-30 10:56
閱讀 1017·2019-08-29 16:59
閱讀 636·2019-08-29 14:04
閱讀 1369·2019-08-29 12:30
閱讀 1089·2019-08-28 18:19
閱讀 566·2019-08-26 11:51