摘要:構(gòu)造器的外表跟普通函數(shù)一樣,他們的區(qū)別在于被調(diào)用的方式。即,使用運(yùn)算符創(chuàng)建對(duì)象時(shí),就是將函數(shù)當(dāng)作構(gòu)造器調(diào)用。本節(jié)內(nèi)容為設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐第二章筆記。
this
JavaScript的this總是指向一個(gè)對(duì)象,至于指向哪個(gè)對(duì)象,是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境的動(dòng)態(tài)綁定的,而非函數(shù)被聲明時(shí)的環(huán)境。
this的指向this的指向大致可以分為以下4類:
作為對(duì)象的方法調(diào)用
作為普通函數(shù)調(diào)用
構(gòu)造器調(diào)用
Function.prototype.call或Function.prototype.apply調(diào)用
1.作為對(duì)象的方法調(diào)用
當(dāng)函數(shù)作為對(duì)象的方法被調(diào)用時(shí),this指向該對(duì)象:
// 聲明obj對(duì)象 var obj = { a: "a屬性的值", // a 屬性 getA: function(){ // getA()方法 console.log(this === obj); // 輸出:true console.log(this.a); // 輸出: a屬性的值 } }; obj.getA();
2.作為普通函數(shù)調(diào)用
當(dāng)函數(shù)不作為對(duì)象的屬性被調(diào)用時(shí),也就是以普通函數(shù)方式,this指向全局對(duì)象。在瀏覽器的JavaScript里,全局對(duì)象是window對(duì)象。
window.name = "globalName"; // 聲明全局對(duì)象的name屬性 var getName = function(){ // 定義getName()函數(shù) return this.name; }; // 調(diào)用函數(shù) console.log(getName()); //輸出: globalName
window.name = "globalName"; // 聲明全局對(duì)象的name屬性 var myObject = { // 聲明myObject對(duì)象 name: "objectName"; getName: function(){ // 定義getName()方法 return this.name; } } var getName = myObject.getName; // 將getName()方法賦給變量getName console.log(getName()); // 輸出: globalName
3.構(gòu)造器調(diào)用
JavaScript沒(méi)有類,但可以從構(gòu)造器中創(chuàng)建對(duì)象,也提供了new運(yùn)算符用于調(diào)用構(gòu)造器。
大部分JavaScript函數(shù)都可以當(dāng)作構(gòu)造器使用。構(gòu)造器的外表跟普通函數(shù)一樣,他們的區(qū)別在于被調(diào)用的方式。即,使用new運(yùn)算符創(chuàng)建對(duì)象時(shí),就是將函數(shù)當(dāng)作構(gòu)造器調(diào)用。當(dāng)用new運(yùn)算符調(diào)用函數(shù)時(shí),該函數(shù)總會(huì)返回一個(gè)對(duì)象,此時(shí),構(gòu)造器里的this指向返回的這個(gè)對(duì)象。
var myClass = function(){ this.name = "className"; }; var obj = new myClass(); console.log(obj.name); // 輸出:seven
但,如果構(gòu)造器顯式地返回了一個(gè)object類型的對(duì)象,那么此函數(shù)將返回這個(gè)object類型的對(duì)象,而不是函數(shù)本身所定義的對(duì)象,例如:
var myClass = function(){ this.name = "className"; return { //顯式地返回一個(gè)對(duì)象 name: "anne" } }; var obj = new myClass(); console.log(obj.name); // 輸出:anne
而,如果構(gòu)造器不顯式地返回任何數(shù)據(jù),或返回一個(gè)非對(duì)象類型的數(shù)據(jù),就不會(huì)造成上述情形。
var myClass = function(){ this.name = "className"; return "anne"; // 返回string類型 }; var obj = new myClass(); console.log(obj.name); // 輸出:className
4.Function.prototype.call 或 Function.prototype.apply調(diào)用
跟普通函數(shù)調(diào)用相比,用 Function.prototype.call 或 Function.prototype.apply 可以動(dòng)態(tài)地改變傳入函數(shù)的this。
var A = { name: "ObjectA", getName: function(){ return this.name; } }; var B = { name: "ObjectB" }; console.log(A.getName()); // 作為對(duì)象的方法調(diào)用,輸出:ObjectA console.log(A.getName.call(B)); // 輸出:ObjectB丟失的this
我們經(jīng)常會(huì)因?yàn)閠his的指向與我們的期待不同,而出現(xiàn)undefined的情況,例如:
var obj = { name: "objName"; getName: function(){ return this.name; } }; // 作為對(duì)象的方法調(diào)用,指向obj對(duì)象 console.log(obj.getName()); // 輸出:objName // 作為普通函數(shù)調(diào)用,指向全局對(duì)象window,name屬性尚未定義 var getName2 = obj.getName; console.log(getName2()); // 輸出:Lundefinedcall 和 apply
ECAMScript3給Function的原型定義了兩個(gè)方法,分別是Function.prototype.call 或 Function.prototype.apply。在一些函數(shù)式風(fēng)格的代碼編寫中,call和apply方法尤為有用。
call和apply的區(qū)別Function.prototype.call 或 Function.prototype.apply的作用一模一樣,區(qū)別僅在于傳入?yún)?shù)形式的不同。
apply接受兩個(gè)參數(shù),第一個(gè)參數(shù)制定了函數(shù)體內(nèi)this對(duì)象的指向,第二個(gè)函數(shù)為一個(gè)帶下標(biāo)的集合,這個(gè)集合可以是數(shù)組,也可以是類數(shù)組。apply方法把這個(gè)集合中的元素作為參數(shù)傳遞給被調(diào)用的函數(shù)。
var func = function(a, b, c){ console.log([a, b, c]); // 輸出:[1,2,3] }; func.apply(null, [1, 2, 3]);
call傳入的參數(shù)數(shù)量不固定,第一個(gè)參數(shù)也是代表了函數(shù)體內(nèi)的this指向,從第二個(gè)參數(shù)開(kāi)始往后,每個(gè)參數(shù)依次被傳入函數(shù):
var func = function(a, b, c){ console.log([a, b, c]); // 輸出:[1,2,3] }; func.call(null, 1, 2, 3);
當(dāng)調(diào)用一個(gè)函數(shù)時(shí),JavaScript的解釋器并不會(huì)計(jì)較形參和實(shí)參在數(shù)量、類型、以及順序上的區(qū)別,JavaScript的參數(shù)在內(nèi)部就是用一個(gè)數(shù)組來(lái)表示的。從這個(gè)意義上說(shuō),apply比call的使用率更高,我們不必關(guān)心具體有多少參數(shù)被傳入函數(shù),只要用apply一股腦地推過(guò)去就可以了。
當(dāng)使用call或apply的時(shí)候,如果我們傳入的第一個(gè)參數(shù)為null,函數(shù)體內(nèi)的this會(huì)指向默認(rèn)的宿主對(duì)象,在瀏覽器中則是window:
var func = function(a, b, c){ console.log(this); }; func.apply(null, [1, 2, 3]); //輸出:window對(duì)象 func.call(null, 1, 2, 3); //輸出:window對(duì)象call和apply的用途
改變this指向
Function.prototype.bind
借用其他對(duì)象的方法
1.改變this指向
call和apply最常見(jiàn)的用途是改變函數(shù)內(nèi)部的this指向:
var A = { name: "nameA"; }; var B = { name: "nameB"; }; window.name = "nameWindow"; var getName = function(){ conlole.log(this.name); }; getName(); // 以普通函數(shù)調(diào)用,指向了window對(duì)象,輸出:nameWindow getName.call(A); // 改變了this的指向,指向了傳入的對(duì)象,輸出:nameA getName.call(B); // 改變了this的指向,指向了傳入的對(duì)象,輸出:nameB
2.Function.prototype.bind
大部分高級(jí)瀏覽器都實(shí)現(xiàn)了內(nèi)置的Function.prototype.bind,用來(lái)指定函數(shù)內(nèi)部的this指向。
若沒(méi)有原生的Function.prototype.bind實(shí)現(xiàn),可以通過(guò)模擬一個(gè):
Function.prototype.bind = function(context){ var self = this; // 保存原函數(shù) return function(){ // 返回一個(gè)新的函數(shù) return self.apply(context, arguments); // 執(zhí)行新函數(shù)的時(shí)候,會(huì)把之前傳入的context當(dāng)作新函數(shù)體內(nèi)的this } }; var obj = { name: "objName" }; var func = function(){ console.log(this.name); // 輸出:objName }.bind(obj); func();
我們通過(guò)Function.prototype.bind來(lái)“包裝”func函數(shù),并且傳入一個(gè)對(duì)象context當(dāng)作參數(shù),這個(gè)context對(duì)象就是我們想要修正的this對(duì)象,即讓函數(shù)內(nèi)部的this指向這個(gè)對(duì)象。
3.借用其他對(duì)象的方法
我們知道,杜鵑即不會(huì)筑巢,也不會(huì)孵雛,而是把自己的蛋寄托給云雀等其他鳥(niǎo)類,讓它們代為孵化和養(yǎng)育。在JavaScript中也存在類似的借用現(xiàn)象。
場(chǎng)景一:借用構(gòu)造函數(shù)
通過(guò)這種技術(shù),能夠?qū)崿F(xiàn)一些類似繼承的效果:
var A = function(name){ this.name = name; }; var B = function(){ // 借用A的構(gòu)造函數(shù) A.apply(this, arguments); }; B.prototype.getName = function(){ return this.name; }; var b = new B("baby"); console.log(b.getName()); // 輸出:baby
場(chǎng)景二:類數(shù)組對(duì)象的操作
函數(shù)的參數(shù)列表arguments是一個(gè)類數(shù)組對(duì)象,雖然它也有下標(biāo),但它并非真正的數(shù)組,所以也不能像數(shù)組一樣,進(jìn)行排序操作或者往集合里添加一個(gè)新的元素。這時(shí),可以借用Array.prototype對(duì)象上的方法。
比如,想往arguments中添加一個(gè)新的元素,可以借用Array.prototype.push:
(function(){ Array.prototype.push.call(arguments, 3); console.log(arguments); // 輸出:[1,2,3] })(1, 2);
想把a(bǔ)rguments轉(zhuǎn)成真正的數(shù)組的時(shí)候,可以借用Array.prototype.slice方法;想截去arguments列表中的頭一個(gè)元素時(shí),可以借用Array.prototype.shift方法。
PS:本節(jié)內(nèi)容為《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》第二章 筆記。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86139.html
摘要:發(fā)布者的狀態(tài)發(fā)生變化時(shí)就會(huì)通知所有的訂閱者,使得它們能夠自動(dòng)更新自己。觀察者模式的中心思想就是促進(jìn)松散耦合,一為時(shí)間上的解耦,二為對(duì)象之間的解耦。參考設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐第章發(fā)布訂閱模式設(shè)計(jì)模式第章第節(jié)觀察者模式 概述 觀察者模式又叫發(fā)布 - 訂閱模式(Publish/Subscribe),它定義了一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)目標(biāo)對(duì)象(為了方便理解,以下將觀察者對(duì)象叫...
摘要:在全局對(duì)象中調(diào)用,自然讀取的是全局對(duì)象的值構(gòu)造器調(diào)用說(shuō)明作為構(gòu)造器調(diào)用時(shí),指向返回的這個(gè)對(duì)象。最直觀的表現(xiàn)就是,去看一些優(yōu)秀框架的源代碼時(shí),不再是被繞的暈乎乎的。 學(xué)習(xí)起因: 在之前的JavaScript學(xué)習(xí)中,this,call,apply總是讓我感到迷惑,但是他們的運(yùn)用又非常的廣泛。遂專門花了一天,來(lái)弄懂JavaScript的this,call,apply。中途參考的書(shū)籍也很多,以...
摘要:注意該方法的作用和方法類似,只有一個(gè)區(qū)別,就是方法接受的是若干個(gè)參數(shù)的列表,而方法接受的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。指定的參數(shù)列表。返回值返回值是你調(diào)用的方法的返回值,若該方法沒(méi)有返回值,則返回。 溫馨提示:作者的爬坑記錄,對(duì)你等大神完全沒(méi)有價(jià)值,別在我這浪費(fèi)生命溫馨提示-續(xù):打call原本是屬于我們偶像宅文化中的專業(yè)名詞,指的是飯們?cè)诳磍ive時(shí)在臺(tái)下配合愛(ài)豆演出的節(jié)奏喊口號(hào),舉例:超...
摘要:訂閱模式的一個(gè)典型的應(yīng)用就是后面會(huì)寫一篇相關(guān)的讀書(shū)筆記。享元模式享元模式的核心思想是對(duì)象復(fù)用,減少對(duì)象數(shù)量,減少內(nèi)存開(kāi)銷。適配器模式對(duì)目標(biāo)函數(shù)進(jìn)行數(shù)據(jù)參數(shù)轉(zhuǎn)化,使其符合目標(biāo)函數(shù)所需要的格式。 設(shè)計(jì)模式 單例模式 JS的單例模式有別于傳統(tǒng)面向?qū)ο笳Z(yǔ)言的單例模式,js作為一門無(wú)類的語(yǔ)言。使用全局變量的模式來(lái)實(shí)現(xiàn)單例模式思想。js里面的單例又分為普通單例和惰性單例,惰性單例指的是只有這個(gè)實(shí)例...
摘要:發(fā)生這種情況的條件是當(dāng)引用類型值的對(duì)象恰好為活躍對(duì)象。總結(jié)本文介紹中的使用,更重要的是幫助我們能更好地理解值在全局函數(shù)構(gòu)造函數(shù)以及一些特例的情況中值的變化。然而,由于對(duì)于來(lái)說(shuō)沒(méi)有任何意義,因此會(huì)隱式轉(zhuǎn)換為全局對(duì)象。 接上一篇Javascript this 的一些學(xué)習(xí)總結(jié)02【轉(zhuǎn)自cnblogs的JKhuang】 引用類型以及this的null值 對(duì)于前面提及的情形,還有例外的情況,當(dāng)調(diào)...
閱讀 3664·2021-10-11 10:58
閱讀 2252·2021-10-08 10:05
閱讀 2035·2021-09-27 13:34
閱讀 3578·2019-08-30 15:53
閱讀 2736·2019-08-30 14:02
閱讀 3564·2019-08-29 16:55
閱讀 625·2019-08-29 15:41
閱讀 1073·2019-08-29 15:23