JavaScript創(chuàng)建對(duì)象的幾種方式及關(guān)于this指向問(wèn)題
工廠模式
工廠模式一般用于抽象創(chuàng)建特定對(duì)象的過(guò)程,是按照特定接口創(chuàng)建對(duì)象的方式。
function createPerson(name, age) { let o = {}; o.name = name; 0.age = age; o.study = function() { console.log(`${this.name} is studying`) } return o } const p1 = createPerson('張三', 18) const p2 = createPerson('李四', 20) p1.study() // 張三 is studying
值得一提的是,如果在 createPerson
函數(shù)中,o.study
改為箭頭函數(shù),那么打印的 this 會(huì)發(fā)生改變,這是因?yàn)榧^函數(shù)發(fā)生了 this
指向的問(wèn)題。
工廠模式的優(yōu)點(diǎn): 在 createPerson
中,可以用不同的參數(shù)多次調(diào)用工廠函數(shù),每次都會(huì)返回包含特定參數(shù)和一個(gè)方法的對(duì)象??梢越鉀Q創(chuàng)建多個(gè)類(lèi)似對(duì)象的問(wèn)題。
工廠模式的缺點(diǎn):
- 1. 沒(méi)有解決對(duì)象標(biāo)識(shí)問(wèn)題。
- 2. 每次創(chuàng)建對(duì)象,都會(huì)創(chuàng)建一個(gè)公共的方法,而方法也是對(duì)象,所以造成內(nèi)存浪費(fèi)。
構(gòu)造函數(shù)模式
在 JS 中, 構(gòu)造函數(shù)是用于創(chuàng)建特定類(lèi)型對(duì)象的。像 Object
、Array
這樣的原生構(gòu)造對(duì)象,運(yùn)行時(shí),可以直接在執(zhí)行環(huán)境中運(yùn)行。當(dāng)然也可以自定義構(gòu)造函數(shù),以函數(shù)的形式為自己的對(duì)象類(lèi)型定義屬性和方法。
function Student(name, age) { this.name = name; this.age = age; this.study = function() { console.log(`${this.name} is studying`) } } const p1 = new Student('張三', 18) const p2 = new Student('李四', 20)
通過(guò)上面的代碼,可以實(shí)現(xiàn)和工廠模式一樣的效果。但是值得注意的是: 如果這里的 study
函數(shù)變?yōu)榧^函數(shù), this
的指向是不會(huì)發(fā)生變化的。
如同上面的代碼,如果調(diào)用構(gòu)造函數(shù),就必須使用 new
關(guān)鍵字,在這個(gè)過(guò)程中,構(gòu)造函數(shù)會(huì)做四件事情:
- 在內(nèi)存中創(chuàng)造一個(gè)新的對(duì)象
- 將這個(gè)新的對(duì)象的隱式原型
__proto__
賦值為該構(gòu)造函數(shù)的顯示原型prototype
- 構(gòu)造函數(shù)的內(nèi)部的
this
被賦值為這個(gè)新的對(duì)象(給新對(duì)象添加新的屬性) - 執(zhí)行構(gòu)造函數(shù)中的代碼,并且判斷有無(wú)對(duì)象返回值,如果存在,則返回這個(gè)返回值,否則返回這個(gè)新的對(duì)象
- 構(gòu)造函數(shù)的優(yōu)缺點(diǎn): 首先,構(gòu)造函數(shù)解決了對(duì)象的標(biāo)識(shí)問(wèn)題,但是如果構(gòu)造函數(shù)中存在著函數(shù),那么每次創(chuàng)建一個(gè)實(shí)例,就相當(dāng)于函數(shù)也被重新創(chuàng)造了一遍,因?yàn)樵贘S中函數(shù)也是相當(dāng)于對(duì)象,造成了對(duì)空間的浪費(fèi)。
關(guān)于 this
在標(biāo)準(zhǔn)函數(shù)中, this 引用的是把函數(shù)當(dāng)成方法調(diào)用的上下文對(duì)象,這個(gè)時(shí)候常稱(chēng)其為 this。
我們?cè)谏衔恼f(shuō)過(guò),工廠模式和構(gòu)造函數(shù)模式,其內(nèi)部如果出現(xiàn)箭頭函數(shù),那么 this
的指向會(huì)出現(xiàn)不同,這是因?yàn)椋^函數(shù)中不存在 this
, 箭頭函數(shù)中的 this
, 會(huì)保留定義該函數(shù)的上下文,this
到底引用哪個(gè)對(duì)象必須到函數(shù)調(diào)用時(shí),才會(huì)確定, 在工廠模式時(shí), 雖然通過(guò)p1.study()
,進(jìn)行調(diào)用,但是由于箭頭函數(shù)內(nèi)部沒(méi)有 this
,所以向上查找,找到function createPerson
函數(shù), 綁定 window
, 而在構(gòu)造函數(shù)模式中this 賦值給了這個(gè)新的對(duì)象,相當(dāng)于箭頭函數(shù)的this
, 就是這個(gè)新的對(duì)象,也就是之后的實(shí)例。
可能,通過(guò)上面的描述,很多同學(xué)仍然對(duì)下面箭頭函數(shù)中的this,會(huì)保留定義該函數(shù)的上下文不太理解,我列舉一個(gè)例子。
// 工廠模式 function createPerson(name, age) { let o = {}; o.name = name; o.age = age; o.study = () => { console.log(`${this.name} is studying`) } return o } const obj = { name: '張三' } const p1 = createPerson.call(obj, '李四', 20) // createPerson 綁定 obj, 那么箭頭函數(shù)也會(huì)綁定 obj p1.study() // 所以這里的輸出是 張三 is studying,而不是 undefined
原型模式
每個(gè)函數(shù)都會(huì)創(chuàng)建一個(gè)
prototype
屬性,這個(gè)屬性是一個(gè)對(duì)象,包含應(yīng)該由特定引用類(lèi)型的實(shí)例共享的屬性和方法。實(shí)際上,這個(gè)對(duì)象就是通過(guò)調(diào)用構(gòu)造函數(shù)創(chuàng)建的對(duì)象的原型。使用原型對(duì)象的好處是,在它上面定義的屬性和方法可以被對(duì)象實(shí)例共享。原來(lái)在構(gòu)造函數(shù)中直接賦值給對(duì)象實(shí)例的值,可以直接賦值給他們的原型。
function Student() {} Student.prototype.name = '張三'; Student.prototype.age = 20; Student.prototype.friends = ['ls', 'ww']; Student.prototype.study = function() { console.log(`${this.name} is studying`) } const p1 = new Student() const p2 = new Student()
通過(guò)上面創(chuàng)建的p1
, p2
,共用了Student
原型上的屬性,相當(dāng)于創(chuàng)造了兩個(gè)擁有相同屬性的不同對(duì)象。同理,如果上面的 study
改為了箭頭函數(shù),大家應(yīng)該也能知道 this
綁定的是誰(shuí)了吧。(Tip: new 和 顯示綁定不可以同時(shí)使用)
原型模式的優(yōu)缺點(diǎn) : 首先原型模式解決了上兩種模式造成的空間浪費(fèi)問(wèn)題,但是,其屬性都是共享的,所以一般來(lái)說(shuō),原型模式不會(huì)單獨(dú)去使用。
- JS創(chuàng)建對(duì)象常用設(shè)計(jì)模式工廠構(gòu)造函數(shù)及原型
- JS對(duì)象創(chuàng)建與繼承的匯總梳理
- java鏈?zhǔn)絼?chuàng)建json對(duì)象的實(shí)現(xiàn)
- JS創(chuàng)建對(duì)象的四種方式
- JavaScript函數(shù)this指向問(wèn)題詳解
- 詳解JavaScript原型對(duì)象的this指向問(wèn)題
- JavaScript 中this指向問(wèn)題案例詳解
- JavaScript函數(shù)中this指向問(wèn)題詳解
- JavaScript中的this指向問(wèn)題詳解
相關(guān)文章
JS前端攻堅(jiān)Eventbus實(shí)現(xiàn)更新示例詳解
這篇文章主要為大家介紹了JS前端攻堅(jiān)Eventbus實(shí)現(xiàn)更新示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12用JavaScript和jQuery實(shí)現(xiàn)瀑布流
本篇文章主要介紹了用JavaScript和jQuery實(shí)現(xiàn)瀑布流的方法,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03JS運(yùn)動(dòng)框架之分享側(cè)邊欄動(dòng)畫(huà)實(shí)例
這篇文章主要介紹了JS運(yùn)動(dòng)框架之分享側(cè)邊欄動(dòng)畫(huà),實(shí)例分析了javascript操作div及css的技巧,需要的朋友可以參考下2015-03-03微信小程序常用簡(jiǎn)易小函數(shù)總結(jié)
這篇文章主要介紹了微信小程序常用簡(jiǎn)易小函數(shù),結(jié)合實(shí)例形式總結(jié)分析了微信小程序提示、登陸、驗(yàn)證、session操作等相關(guān)操作函數(shù)與使用技巧,需要的朋友可以參考下2019-02-02JavaScript Array.flat()函數(shù)用法解析
這篇文章主要介紹了JavaScript Array.flat()函數(shù)用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09詳解JavaScript原始數(shù)據(jù)類(lèi)型Symbol
以前提到 JavaScript 原始數(shù)據(jù)類(lèi)型時(shí),我們知道有Number,String,Null,Boolean,Undefined這幾種。ES6 引入了新的基本數(shù)據(jù)類(lèi)型Symbol和BigInt。今天我們就來(lái)了解下Symbol類(lèi)型。Symbol類(lèi)型是為了解決屬性名沖突的問(wèn)題,順帶還具備模擬私有屬性的功能。2021-05-05利用JavaScript實(shí)現(xiàn)仿QQ個(gè)人資料卡效果
這篇文章主要為大家詳細(xì)介紹了如何利用HTML+CSS+JavaScript實(shí)現(xiàn)仿QQ個(gè)人資料卡效果,文中的示例代碼講解詳細(xì),感興趣的可以動(dòng)手嘗試一下2022-08-08MVVM模式中ViewModel和View、Model有什么區(qū)別?
這篇文章主要介紹了MVVM模式中ViewModel和View、Model有什么區(qū)別?本文分別解釋了它們的功能和作用,然后總結(jié)了它之間的區(qū)別,需要的朋友可以參考下2015-06-06