日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript设计模式与开发实践 | 02 - this、call和apply

發(fā)布時(shí)間:2024/1/17 javascript 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript设计模式与开发实践 | 02 - this、call和apply 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

this

JavaScript的this總是指向一個(gè)對象,至于指向哪個(gè)對象,是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境的動(dòng)態(tài)綁定的,而非函數(shù)被聲明時(shí)的環(huán)境。

this的指向

this的指向大致可以分為以下4類:

  • 作為對象的方法調(diào)用

  • 作為普通函數(shù)調(diào)用

  • 構(gòu)造器調(diào)用

  • Function.prototype.call或Function.prototype.apply調(diào)用

1.作為對象的方法調(diào)用

當(dāng)函數(shù)作為對象的方法被調(diào)用時(shí),this指向該對象:

// 聲明obj對象 var obj = {a: 'a屬性的值', // a 屬性getA: function(){ // getA()方法console.log(this === obj); // 輸出:trueconsole.log(this.a); // 輸出: a屬性的值} };obj.getA();

2.作為普通函數(shù)調(diào)用

當(dāng)函數(shù)不作為對象的屬性被調(diào)用時(shí),也就是以普通函數(shù)方式,this指向全局對象。在瀏覽器的JavaScript里,全局對象是window對象。

window.name = 'globalName'; // 聲明全局對象的name屬性var getName = function(){ // 定義getName()函數(shù)return this.name; };// 調(diào)用函數(shù) console.log(getName()); //輸出: globalName window.name = 'globalName'; // 聲明全局對象的name屬性var myObject = { // 聲明myObject對象name: 'objectName';getName: function(){ // 定義getName()方法return this.name;} }var getName = myObject.getName; // 將getName()方法賦給變量getNameconsole.log(getName()); // 輸出: globalName

3.構(gòu)造器調(diào)用

JavaScript沒有類,但可以從構(gòu)造器中創(chuàng)建對象,也提供了new運(yùn)算符用于調(diào)用構(gòu)造器。

大部分JavaScript函數(shù)都可以當(dāng)作構(gòu)造器使用。構(gòu)造器的外表跟普通函數(shù)一樣,他們的區(qū)別在于被調(diào)用的方式。即,使用new運(yùn)算符創(chuàng)建對象時(shí),就是將函數(shù)當(dāng)作構(gòu)造器調(diào)用。當(dāng)用new運(yùn)算符調(diào)用函數(shù)時(shí),該函數(shù)總會(huì)返回一個(gè)對象,此時(shí),構(gòu)造器里的this指向返回的這個(gè)對象。

var myClass = function(){this.name = 'className'; };var obj = new myClass(); console.log(obj.name); // 輸出:seven

但,如果構(gòu)造器顯式地返回了一個(gè)object類型的對象,那么此函數(shù)將返回這個(gè)object類型的對象,而不是函數(shù)本身所定義的對象,例如:

var myClass = function(){this.name = 'className';return { //顯式地返回一個(gè)對象name: 'anne'} };var obj = new myClass(); console.log(obj.name); // 輸出:anne

而,如果構(gòu)造器不顯式地返回任何數(shù)據(jù),或返回一個(gè)非對象類型的數(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()); // 作為對象的方法調(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;} };// 作為對象的方法調(diào)用,指向obj對象 console.log(obj.getName()); // 輸出:objName// 作為普通函數(shù)調(diào)用,指向全局對象window,name屬性尚未定義 var getName2 = obj.getName; console.log(getName2()); // 輸出:Lundefined

call 和 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對象的指向,第二個(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ù)開始往后,每個(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ù)組來表示的。從這個(gè)意義上說,apply比call的使用率更高,我們不必關(guān)心具體有多少參數(shù)被傳入函數(shù),只要用apply一股腦地推過去就可以了。

當(dāng)使用call或apply的時(shí)候,如果我們傳入的第一個(gè)參數(shù)為null,函數(shù)體內(nèi)的this會(huì)指向默認(rèn)的宿主對象,在瀏覽器中則是window:

var func = function(a, b, c){console.log(this); };func.apply(null, [1, 2, 3]); //輸出:window對象 func.call(null, 1, 2, 3); //輸出:window對象

call和apply的用途

  • 改變this指向

  • Function.prototype.bind

  • 借用其他對象的方法

1.改變this指向

call和apply最常見的用途是改變函數(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對象,輸出:nameWindow getName.call(A); // 改變了this的指向,指向了傳入的對象,輸出:nameA getName.call(B); // 改變了this的指向,指向了傳入的對象,輸出:nameB

2.Function.prototype.bind

大部分高級瀏覽器都實(shí)現(xiàn)了內(nèi)置的Function.prototype.bind,用來指定函數(shù)內(nèi)部的this指向。
若沒有原生的Function.prototype.bind實(shí)現(xiàn),可以通過模擬一個(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();

我們通過Function.prototype.bind來“包裝”func函數(shù),并且傳入一個(gè)對象context當(dāng)作參數(shù),這個(gè)context對象就是我們想要修正的this對象,即讓函數(shù)內(nèi)部的this指向這個(gè)對象。

3.借用其他對象的方法

我們知道,杜鵑即不會(huì)筑巢,也不會(huì)孵雛,而是把自己的蛋寄托給云雀等其他鳥類,讓它們代為孵化和養(yǎng)育。在JavaScript中也存在類似的借用現(xiàn)象。

場景一:借用構(gòu)造函數(shù)
通過這種技術(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

場景二:類數(shù)組對象的操作
函數(shù)的參數(shù)列表arguments是一個(gè)類數(shù)組對象,雖然它也有下標(biāo),但它并非真正的數(shù)組,所以也不能像數(shù)組一樣,進(jìn)行排序操作或者往集合里添加一個(gè)新的元素。這時(shí),可以借用Array.prototype對象上的方法。

比如,想往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ì)模式與開發(fā)實(shí)踐》第二章 筆記。

總結(jié)

以上是生活随笔為你收集整理的JavaScript设计模式与开发实践 | 02 - this、call和apply的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。