最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

老生常談JavaScript設計模式之call,apply,this詳解

 更新時間:2025年06月01日 09:39:23   作者:天生我材必有用_吳用  
這篇文章主要介紹了JavaScript設計模式之call,apply,this的相關知識,本文通過示例代碼給大家介紹的非常詳細,需要的朋友可以參考下

前言:

最近在看曾探老師的《JavaScript設計模式》,說實話,可能是我基礎還不夠扎實,書里的很多內容對我來說不是“一看就懂”,而是“看了三遍才懂一點點”。特別是像代碼邏輯、概念解釋這些地方,常常是一次看不懂,就來兩次;兩次還迷糊,就再來一次。但我慢慢也想通了,學習本來就是一個不斷重復的過程。每一次重讀,都能從字里行間中發(fā)現新的理解,就像挖寶藏一樣,每次翻一翻都有新收獲。為了讓自己記得更牢,也為了讓以后復習的時候不那么枯燥,我在反復閱讀第二章“this、call、apply”之后,試著用自己的話,把知識點編成了一個小故事的形式,講給自己聽。
我想,這不僅是一種學習方式,也是我對這本書的一種致敬。

this找家

想象一下,this就像是一個四處旅行的人,他總在尋找它的“家”,但是問題來了,這個人(this)的家并不固定,取決于他是怎么被邀請這個地方的,在javaScript中,this就是一個旅行者,他的指向完全依賴于函數的調用方式。

如果是對象的方法調用:比如obj.myMethod(),那么this的家就安在obj里面。
如果是作為構造函數調用:比如new MyClass(),這時候this就有了自己的新家,一個新的對象實例
如果是直接調用函數,比如myFunction(),那么嚴格模式下,this就會變得無家可歸,即undefined,而在非嚴格模式下,則默認回到了全局對象瀏覽器的window的懷抱。

call 和 apply 導游

現在,比如我們的this旅行者到了一個陌生的城市,不知道如何找到正確的家,這時候就可以請callapply兩位熱心的導游出現了。
call這個導游很細心,他會親自帶著this去正確的地方,并且還允許你指定額外的參數列表,就像myFunction.call(context,arg1,arg2)。在這里,context就是我們希望this去的家,而后面參數就是這次旅行所需要的裝備。
applycall不同的是,apply更喜歡一次性把所有的東西都準備好再出發(fā),所以除了第一個參數用來指定this應該去的"家"外,它接收第二個參數為一個數組或類數組對象,里面包含了所需要傳遞給函數的參數,如myFunction.apply(context,[arg1,arg2]),總之,當你想要控制this的指向,或者需要特定的方式傳遞參數的時候,callapply就是你的得力導游,他們不僅能幫this找到回家的路,還能確保旅途愉快順利。

this的指向

第一站、作為對象的方法被調用(this回到家)

有一天,this被一個叫做obj的大叔收留了,成為了大叔家的傭人。

var obj = {
    a: 1,
    getA: function() {
        console.log(this === obj); // true
        console.log(this.a);       // 1
    }
};
obj.getA();

著obj家里,this每天多的都很開心,this開心的喊:“我終于找到加啦!我是obj家的孩子”,因為他是在obj家里被調用的,所以他就是的孩子。

第二站、普通函數調用(this離家出走)

但是有一天,this不小心跑出了obj的家,在外面遇到一個叫getName的陌生人:

var getName = obj.getName;
getName(); // 輸出 undefined 或 globalName

??這時候的this已經不是obj的孩子了,他又變成了流浪漢,回到了全局大哥window家,不過別擔心,如果this在全局如果window家過的不開心,可以開啟"use strict"【嚴格模式】模式,this更加自尊自愛,寧愿當個“無家可歸的孤獨者”,也不愿意隨便認爹! 很有骨氣吧,用孤獨換的骨氣 哈哈哈。

第三站、構造器調用(this自己當爹)

后來啊,有骨氣的this長大了,學會了獨立,決定自己當爸爸!

function Person(name) {
    this.name = name;
}
var tom = new Person('Tom');
console.log(tom.name); // Tom

結果this發(fā)現,自己辛辛苦苦當的爹,娃娃居然被別人搶走了。

第四站、Function.prototype.call 或 Function.prototype.apply 調用

這時候,兩位神秘人物登場了,他們就是大名鼎鼎JavaScript劇場的導演call和apply!,他們告訴this:“this你很堅強,我們被你打動了,現在開始,你想演誰都可以,我?guī)湍銚Q身份。”,于是:

var obj1 = { name: '鋼鐵俠' };
var obj2 = { name: '蜘蛛俠' };
function sayHi() {
    console.log("我是" + this.name);
}
sayHi.call(obj1);   // 我是鋼鐵俠
sayHi.apply(obj2);  // 我是蜘蛛俠

this得到兩位大哥的幫助,開始在不同的角色之間切換,一會是鋼鐵俠,一會是蜘蛛俠,忙的不亦樂乎,體驗那種既可以當英雄,又可以有家的感覺。
有一天,this在div家做客,突然被一個叫做callback的函數騙走了身份信息:

<div id="div1">我是一個 div</div>
<script>
document.getElementById('div1').onclick = function () {
    alert(this.id); // div1 ?
    var callback = function () {
        alert(this.id); // window ?
    }
    callback();
};
</script>

這個時候,this又跑回了window家,而它本應該屬于哪個div,怎么辦呢,this想了個辦法:

var that = this;
var callback = function () {
    alert(that.id); // div1 ?
}

就像this孩子給自己辦一張身份證,再也不怕他迷路啦。

修復 document.getElementById 的 this

有一次,this被借去演習,結果卻跑到了document.getElementById里面,導致整個劇組都亂了套。

<html> 
 <body> 
 <div id="div1">我是一個 div</div> 
 </body> 
 <script> 
 var getId = document.getElementById; 
 getId( 'div1' );   // 報錯,this不在指向document
 </script> 
</html>

getId( ‘div1’ );就會報錯,this不在指向document,原來this應該是docuement家的人,結果卻被當成window使用了,apply導演不舍得this,就決定動用自己的能力,立刻修復:

document.getElementById = (function( func ){ 
 return function(){ 
 return func.apply( document, arguments ); 
 } 
})( document.getElementById ); 
var getId = document.getElementById; 
var div = getId( 'div1' ); 
alert (div.id); // 輸出: div1

終于,this回到了正確的家庭,拯救了整個劇組,經過這次慘痛的教訓,導演對這次事故進行分析總結:

在這里插入圖片描述

導演發(fā)現,在Chrome執(zhí)行過后發(fā)現,var getId = document.getElementById拋出了一個異常,因為許多的引擎document.getElementById方法的內部實現張需要用到this。這個this本來被期望指向document,當getElementById方法作為document對象的屬性被調用時,方法內部的this確實是指向document的,但是當getId來引用document.getElementById之后,再調用getId,此時就成了普通函數調用,函數內部的this指向了Window,而不是原來的document。
導演發(fā)現可以使用apply,把document當作this傳入getId函數,幫助“修正”this

 <script>
 document.getElementById = (function (func) {
    return function () {
      return func.apply(document, arguments);
    };
  })(document.getElementById);
  var getId = document.getElementById;
  var div = getId("div1");
  alert(div.id); // 輸出: div1
</script>

深入理解JavaScript設計模式之call,apply,this的深入理解


終于通過導演的不懈努力與分析讓this回到了正確的家庭總結了整個劇組,甚至還總結了口訣:

this是誰調用了我,我就跟誰混。
call/applythis的導演,想讓this演誰都可以。

發(fā)生了上面的事情之后,this學會了如何在javaScript世界中找到自己的歸屬,它不再輕易迷路,也不再害怕被借來借去,從此要記住:

多問問this:“whu ar you ?" 你是誰?多請callapply來幫忙。別忘了用bindthat=thisthis上個保險!

call和Apply

Apply序

apply是一個豪放派的導演,他習慣把所有演員打包成一個團隊(數組或類數組),然后一次性推到主演面前。

func.apply(thisArg, [arg1, arg2, ...]);

盡管風格不同,但是目標是一致的,幫助函數找到正確的舞臺背景(改變this的指向),并讓每個演員都能發(fā)揮最大的作用(正確的傳遞)。

Apply正文:

apply接收兩個參數,第一個參數指定了函數體內this的指向,第二個參數為一個帶下標的集合,這個集合可以為數組,也可以為類數組,apply方法把這個結合中的元素作為參數傳遞給被調用的函數:

var func = function( a, b, c ){ 
 alert ( [ a, b, c ] ); // 輸出 [ 1, 2, 3 ] 
}; 
func.apply( null, [ 1, 2, 3 ] ); 

在這段代碼中,參數 1、2、3 被放在數組中一起傳入 func 函數,它們分別對應 func 參數列表中的 a、b、c

call序

call是一位細心講究的導演,他喜歡把演員(參數)一個個親自介紹給主演(函數),確保每個演員都有明確的角色。

func.call(thisArg, arg1, arg2, ...);

call正文:

call傳入的參數數量不固定,跟apply相同的是,第一個參數也是代表函數體內的this指向,從第二個參數開始往后,每個參數被依次傳入函數:

var func = function( a, b, c ){ 
 alert ( [ a, b, c ] ); // 輸出 [ 1, 2, 3 ] 
}; 
func.call( null, 1, 2, 3 );

當調用一個函數的時候,JavaScript的解釋器并不會計較形參和實參的數量、類型、以及順序上的區(qū)別,JavaScript的參數在內部就用一個數組來表示的,從這個意義上說,applycall使用率更高,不必關心具體多少個參數被傳入函數,只要作用apply一股腦地推過去即可。

注意:

當使用call或者apply的時候,如果我們傳入的第一個參數為null,函數體內的this會默認值想宿主對象,在瀏覽器中則是windows

Function.prototype.bind

Function.prototype.bind是一個秘密裝備,能讓你隨心所欲的控制函數內部的this指向,即使在遙遠的地方調用這個函數時也能保持“它”的初心,首先我們要打造一個屬于自己的 Function.prototype.bind我們先把 func 函數的引用保存起來,然后返回一個新的函數。當我們在將來執(zhí)行 func 函數時,實際上先執(zhí)行的是這個剛剛返回的新函數。在新函數內部,self.apply( context, arguments )這句代碼才是執(zhí)行原來的 func 函數,并且指定 context對象為 func 函數體內的 this。

Function.prototype.bind = function(context) { 
    var self = this; // 保存原函數,就像把寶劍藏在腰間
    return function() { // 返回一個新的函數,這就是我們的新武器
        return self.apply(context, arguments); // 當使用這把寶劍時,它會自動指向正確的方向
    } 
}; 
var obj = { name: 'sven' }; // 我們的英雄 sven
var func = function() { 
    alert(this.name); // 輸出:sven
}.bind(obj); 
func(); // 英雄登場!

上面代碼中,bind就像給函數穿上了一層魔法鎧甲,無論什么時候,只要調用它,它就會帶著obj的這個身份出現。但是,真正的超級英雄不能只有一技之長!我們需要讓 bind更加強大,讓它不僅能綁定 this,還能預先填入一些參數。這就像是給我們的寶劍裝上了“魔法石”,讓它變得更強大:

Function.prototype.bind = function() { 
    var self = this, // 保存原函數
        context = [].shift.call(arguments), // 需要綁定的 this 上下文,也就是英雄的身份
        args = [].slice.call(arguments); // 把剩下的參數轉換成數組,作為魔法石
    return function() { // 返回一個新的函數,這是我們的終極武器
        return self.apply(context, [].concat.call(args, [].slice.call(arguments))); 
        // 組合兩次傳入的參數,作為新函數的參數
    } 
}; 
var obj = { name: 'sven' }; // 英雄 sven 再次登場
var func = function(a, b, c, d) { 
    alert(this.name); // 輸出:sven
    alert([a, b, c, d]); // 輸出:[1, 2, 3, 4]
}.bind(obj, 1, 2); 
func(3, 4); // 召喚英雄,帶上所有的魔法石!

改變 this 指向:為函數找到真正的家

在一個戲劇性的場景中,有一名為getName的函數,它渴望知道自己到底屬于哪個家族:

var obj1 = { name: 'sven' };
var obj2 = { name: 'anne' };
window.name = 'global';
function getName() {
    alert(this.name);
}
getName(); // 輸出: global
// 現在,Call 導演登場,幫助 getName 找到了它的真正歸屬——obj1 家族
getName.call(obj1); // 輸出: sven

通過callapply大導演的幫助下,getName終于找到了它真正的家!

借用其他對象的方法:杜鵑鳥的智慧

JavaScript中也有一種"借殼生蛋"的藝術,就像杜鵑鳥將自己的蛋托付給其他鳥類孵化一樣,這里callapply也能幫我們借用其他對象的方法來完成一些任務。
例1:

var A = function( name ){ 
 this.name = name; 
}; 
var B = function(){ 
 A.apply( this, arguments ); 
}; 
B.prototype.getName = function(){ 
 return this.name; 
}; 
var b = new B( 'sven' ); 
console.log( b.getName() ); // 輸出: 'sven'

上面例子中,B借用了A的構造函數邏輯來初始化自己的實例屬性,可以說是繼承了A的部分功能,準確來說是構造函數繼承借用構造函數。
函數的參數列表 arguments 是一個類數組對象,雖然它也有“下標”,但它并非真正的數組,所以也不能像數組一樣,進行排序操作或者往集合里添加一個新的元素。

我們常常會借用 Array.prototype 對象上的方法。比如想往 arguments 中添加一個新的元素,通常會借用Array.prototype.push

(function() {
    Array.prototype.push.call(arguments, 3);
    console.log(arguments); // 輸出: [1, 2, 3]
})(1, 2);

Call 導演巧妙地讓 Array.prototype.push 方法在非數組的對象上施展魔法,成功地添加了一個新成員。

無論是改變this的指向,還是靈活地傳遞參數,甚至是借用其他對象的方法,CallApply 總能以其獨特的技巧讓每一個函數都成為舞臺上的明星。

到此這篇關于老生常談JavaScript設計模式之call,apply,this的文章就介紹到這了,更多相關js call,apply,this內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • JS+canvas畫布實現炫酷的旋轉星空效果示例

    JS+canvas畫布實現炫酷的旋轉星空效果示例

    這篇文章主要介紹了JS+canvas畫布實現炫酷的旋轉星空效果,結合實例形式分析了js結合HTML5 canvas圖形繪制與數值計算相關操作技巧,需要的朋友可以參考下
    2019-02-02
  • js實現簡單廣告小窗口

    js實現簡單廣告小窗口

    這篇文章主要為大家詳細介紹了js實現簡單廣告小窗口,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • JS實現密碼框根據焦點的獲取與失去控制文字的消失與顯示效果

    JS實現密碼框根據焦點的獲取與失去控制文字的消失與顯示效果

    這篇文章主要介紹了JS實現密碼框根據焦點的獲取與失去控制文字的消失與顯示效果,可實現使用JavaScript判斷密碼框是否獲得焦點來隱藏與顯示提示文字,非常簡單實用,需要的朋友可以參考下
    2015-11-11
  • 微信小程序商城項目之淘寶分類入口(2)

    微信小程序商城項目之淘寶分類入口(2)

    這篇文章主要為大家詳細介紹了微信小程序實戰(zhàn)商城系列之淘寶分類入口,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Bootstrap柵格系統(tǒng)簡單實現代碼

    Bootstrap柵格系統(tǒng)簡單實現代碼

    這篇文章主要為大家詳細介紹了Boostrap柵格系統(tǒng)的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Event altKey,ctrlKey,shiftKey屬性解析

    Event altKey,ctrlKey,shiftKey屬性解析

    本篇文章主要是對Event altKey,ctrlKey,shiftKey屬性解析了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • 深入探討如何利用Canvas實現圖片壓縮與Base64轉換

    深入探討如何利用Canvas實現圖片壓縮與Base64轉換

    隨著Web應用的日益普及,圖片的處理和優(yōu)化已經成為現代開發(fā)的關鍵部分,本文主要介紹了如何利用Canvas技術,將圖片進行壓縮,并將其轉換為Base64格式,感興趣的小伙伴可以學習下
    2023-10-10
  • js怎么判斷是否是數組的六種方法小結

    js怎么判斷是否是數組的六種方法小結

    本文主要介紹了js怎么判斷是否是數組的六種方法小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • JS簡單實現動態(tài)添加HTML標記的方法示例

    JS簡單實現動態(tài)添加HTML標記的方法示例

    這篇文章主要介紹了JS簡單實現動態(tài)添加HTML標記的方法,結合實例形式分析了JavaScript使用createElement()方法針對頁面元素進行動態(tài)操作相關實現技巧,需要的朋友可以參考下
    2018-04-04
  • 關于JavaScript奇怪又實用的六個姿勢

    關于JavaScript奇怪又實用的六個姿勢

    這篇文章主要給大家介紹了關于JavaScript奇怪又實用的六個姿勢,這些技巧和建議是我平常在開發(fā)項目上會用到的,希望能讓大家學到知識,需要的朋友可以參考下
    2021-10-10

最新評論

特克斯县| 南皮县| 屏东县| 鸡东县| 郴州市| 洛隆县| 武宣县| 海晏县| 巴里| 抚远县| 清原| 盐城市| 句容市| 万宁市| 梁平县| 钟祥市| 昌平区| 宁晋县| 寿光市| 睢宁县| 彰化县| 新竹市| 丰镇市| 鹤峰县| 水城县| 诏安县| 岢岚县| 桐梓县| 布拖县| 桃江县| 北宁市| 建水县| 久治县| 永和县| 吉首市| 临汾市| 兴宁市| 喀喇沁旗| 任丘市| 綦江县| 郓城县|