摘要:文章盡量使用大量實例進行講解,它們的使用場景。在嚴(yán)格模式下,函數(shù)被調(diào)用后,里面的默認(rèn)是后面通過調(diào)用函數(shù)上的和方法,該變指向,函數(shù)里面的指向。利用,可以傳入外層的上下文。同樣適用的還有,里面的對象,它也是一種類數(shù)組對象。
call,apply and bind in JavaScript
在ECMAScript中,每個函數(shù)都包含兩個繼承而來的方法:apply() 和 call(),這兩個方法的用途都是在特定的作用域中調(diào)用函數(shù),主要作用跟bind一樣,用來改變函數(shù)體內(nèi)this的指向,或者說是在函數(shù)調(diào)用時改變上下文。
文章盡量使用大量實例進行講解,它們的使用場景。同時,也會由淺入深的引導(dǎo)出一些理論,畢竟這幾個常用方法,在MDN上都能找到合理的解釋
基本功能 改變this的指向var fruit = { fruitName:"apple" } function getFruit() { console.log("I like "+this.fruitName) } getFruit(); // log I like undefined getFruit.call(fruit) // log I like apple getFruit.apply(fruit) // log I like apple var newBind = getFruit.bind(fruit) newBind(); // log I like apple
當(dāng) getFruit 并非作為一個對象的屬性,而是直接當(dāng)做一個函數(shù)來調(diào)用,里面的this就會被綁定到全局對象上,即window上, 所以直接調(diào)用 getFruit,里面的this指向了全局對象上,返回 undefined。
在嚴(yán)格模式下,函數(shù)被調(diào)用后,里面的this默認(rèn)是 undefined
后面,通過調(diào)用函數(shù)上的call和apply方法,該變this指向,函數(shù)里面的this指向fruit。
區(qū)別:
bind同樣實現(xiàn)了改變this指向的功能,但是它不會立即執(zhí)行,而是會重新創(chuàng)建一個綁定函數(shù),新函數(shù)被調(diào)用時,使用bind()方法里面的第一個參數(shù)作為this
這三個方法,從接受的第二參數(shù)開始,都直接傳遞給函數(shù),但是接受參數(shù)的方法卻很大的不同。
call,從第二個參數(shù)開始,以參數(shù)列表的形式展示,
apply,則把傳遞的函數(shù)參數(shù),放在一個數(shù)組里面作為第二個參數(shù)。
fn.call(obj,arg1,arg2); fn.apply(obj,[arg1,arg2])
bind,從第二個參數(shù)開始,同樣以參數(shù)列表的形式,但是會提前放在新綁定函數(shù)的參數(shù)之前
var foo = function(name,age){ console.log("name: "+name+"- age: "+age) } var p1 = foo.bind(this,"popo"); // "popo" 作為新函數(shù)的第一個參數(shù)。 p1(13); // logs name: popo- age: 13 p1("bobo",14) // logs name: popo- age: bobo應(yīng)用場景
綁定事件回調(diào)中
$(".div-class").on("click",function(event) { /*TODO*/ }.bind(this)); } }
通常,我們在改變函數(shù)上下文之前,都會使用類似that = this,或者self,_this,來把this賦值給一個變量。利用.bind(),可以傳入外層的上下文。
循環(huán)回調(diào)
循環(huán)中利用閉包來處理回調(diào)
for(var i = 0;i < 10;i++){ (function(j){ setTimeout(function(){ console.log(j); },600); })(i) }
每次循環(huán),都會產(chǎn)生一個立即執(zhí)行的函數(shù),函數(shù)內(nèi)部的局部變量j保存不同時期i的值,循環(huán)過程中,setTimeout回調(diào)按順序放入消息隊列中,等for循環(huán)結(jié)束后,堆棧中沒有同步的代碼,就去消息隊列中,執(zhí)行對應(yīng)的回調(diào),打印出j的值。
同理,可以利用bind,每次都創(chuàng)建新的函數(shù),并且已經(jīng)預(yù)先設(shè)置了參數(shù),傳入不同的指針
function func(i) { console.log(i) } for(var i =0 ;i< 10;i++) { setTimeout(func.bind(null,i),600) }
實現(xiàn)繼承
var Person = function(name,age) { this.name = name; this.age = age; } var P1 = function(name,age) { // 借用構(gòu)造函數(shù)的方式實現(xiàn)繼承 // 利用call 繼承了Person Person.call(this,name,age) } P1.prototype.getName = function() { console.log("name: "+this.name+", age: "+this.age); } var newPerson = new P1("popo",20); // logs name: popo, age: 20 newPerson.getName();
實質(zhì)上,可以看成通過call()或者apply()方法,在即將新建的對象,即這里的newPerson上,執(zhí)行超類型的構(gòu)造函數(shù),分別在當(dāng)前上下文this上添加name和age屬性。
數(shù)組驗證的終極方法
function isArray(value) { return Object.prototype.toString.call(value) == "[object Array]" }
借用了Object原生的toString()方法,打印出對應(yīng)變量的構(gòu)造函數(shù)名,
類數(shù)組轉(zhuǎn)換為數(shù)組
// 實現(xiàn)一個簡單的數(shù)組 "unshift"方法 Array.prototype.unshift = function(){ this.splice.apply(this, [0,0].concat(Array.prototype.slice.apply(arguments))); return this.length; }
首先,利用this.splice.apply(),其中splice,可以直接從數(shù)組中移除或者插入變量。apply()則以數(shù)組的形式傳遞參數(shù),需要利用concat拼接數(shù)組。
當(dāng)函數(shù)被調(diào)用時,在函數(shù)內(nèi)部會得到類數(shù)組arguments,它擁有一個length屬性,但是沒有任何數(shù)組的方法。所以,將slice方法中的this指向arguments,獲取到arguments的長度,從而確定方法的start和end下標(biāo),得到一個數(shù)組變量。
同樣適用的還有,DOM里面的NodeList對象,它也是一種類數(shù)組對象。
深入理解 實現(xiàn)bind 方法bind方法在ECMAScript5里面被引入,前面提到過,調(diào)用該方法時,返回一個新的函數(shù),可以簡單使用下面方法實現(xiàn)其改變this指向的功能。
Function.prototype.bind = function(scope) { var fn = this; return function() { return fn.apply(scope) } }
接著,就可以利用concat把bind傳遞的預(yù)置參數(shù)拼接到新函數(shù)的參數(shù)列表中。
Function.prototype.bind = function(scope) { var args = Array.prototype.slice.call(arguments,1) var fn = this return function() { return fn.apply(scope,args.concat(Array.prototype.slice.call(arguments))) } }
參考鏈接
Javascript之bind
Understanding JavaScript Bind ()
深入淺出妙用 Javascript 中 apply、call、bind
前端基礎(chǔ)進階:全方位解讀 this
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/93371.html
摘要:理解文章中已經(jīng)比較全面的分析了在中的指向問題,用一句話來總結(jié)就是的指向一定是在執(zhí)行時決定的,指向被調(diào)用函數(shù)的對象。與和直接執(zhí)行原函數(shù)不同的是,返回的是一個新函數(shù)。這個新函數(shù)包裹了原函數(shù),并且綁定了的指向為傳入的。 理解 JavaScript this 文章中已經(jīng)比較全面的分析了 this 在 JavaScript 中的指向問題,用一句話來總結(jié)就是:this 的指向一定是在執(zhí)行時決定的,...
摘要:關(guān)于在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了的值。不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時的值也可能會不同。它們除了參數(shù)略有不同,其功能完全一樣。它們的第一個參數(shù)都為將要指向的對象。 關(guān)于 this 在絕大多數(shù)情況下,函數(shù)的調(diào)用方式?jīng)Q定了this的值。this不能在執(zhí)行期間被賦值,并且在每次函數(shù)被調(diào)用時this的值也可能會不同。 全局 this window.something = ...
摘要:閉包閉包的概念與詞法域關(guān)系緊密。閉包甚至在函數(shù)已經(jīng)返回后也可以獲取其外部函數(shù)的變量。一種常見的閉包導(dǎo)致的由立即調(diào)用函數(shù)表達(dá)式解決的例子事實上結(jié)果的所有都是,而不是按順序得出的,。 介紹 JavaScript 有一個特征————作用域。理解作用域scope可以使你的代碼脫穎而出,減少錯誤,幫助你用它構(gòu)造強大的設(shè)計模式。 什么是作用域 作用域就是在代碼執(zhí)行期間變量,函數(shù)和對象能被獲取到的特...
I thought I know the Function definition, execution context and the behavior of this in JavaScript. However, I realized that actually I dont or the knowlege is still not firmly grounded in my mind wh...
摘要:至于,其只是以數(shù)組的方傳入?yún)?shù),其它部分是一樣的,如下它們也可用于在中的類繼承中,調(diào)用父級構(gòu)造器。間接調(diào)用,調(diào)用了父級構(gòu)造器對比方法和,它倆都立即執(zhí)行了函數(shù),而函數(shù)返回了一個新方法,綁定了預(yù)先指定好的,并可以延后調(diào)用。 其實this是一個老生常談的問題了。關(guān)于this的文章非常多,其實我本以為自己早弄明白了它,不過昨天在做項目的過程中,還是出現(xiàn)了一絲疑惑,想到大概之前在JavaScri...
閱讀 561·2023-04-26 02:58
閱讀 2301·2021-09-27 14:01
閱讀 3605·2021-09-22 15:57
閱讀 1168·2019-08-30 15:56
閱讀 1043·2019-08-30 15:53
閱讀 787·2019-08-30 15:52
閱讀 645·2019-08-26 14:01
閱讀 2157·2019-08-26 13:41