摘要:眾所周知,這三個(gè)函數(shù)都是改變執(zhí)行上下文的,那么我們來捋一捋,這些函數(shù)內(nèi)部到底做了什么。
前言
稍微翻了一下call,apply, bind 的各種論壇上的文章, 發(fā)現(xiàn)講的都太淺了,大部分都只講了個(gè)用法, 對(duì)于實(shí)現(xiàn)的原理卻都沒有提,因此,在這里,我寫下這篇文章, 希望能讓大家認(rèn)識(shí)到原理所在。
眾所周知, 這三個(gè)函數(shù)都是改變執(zhí)行上下文的 , 那么我們來捋一捋,這些函數(shù)內(nèi)部到底做了什么。
callFunction是函數(shù)對(duì)象的構(gòu)造方法,call,apply,bind 都是函數(shù)原型上的方法 作為實(shí)例 他自身也有這三個(gè)方法
圈中的為原型方法, 方塊的為實(shí)例方法,另外length屬性就是argument的長(zhǎng)度,我們通常調(diào)用一個(gè)函數(shù)
function a(){ console.log(this,"a")}; function b(b){console.log(b)} a.call(b,"我是B的參數(shù)")
執(zhí)行a, 并把context指向b, 這里大家都沒有疑問, 那么問題來了
function a(){ console.log(this,"a")}; function b(){console.log(this,"b")} a.call.call.call(b,"b") // 這個(gè)結(jié)果是什么呢? 答案是
傻眼了吧 ? 怎么執(zhí)行了B 并且this指向了這個(gè) b字符串
我們來分析一下 call是原型上的方法 那么a.call 他本身也是一個(gè)函數(shù) 所以a.call.call.call 不就是a.call.call的原型上的call方法么?
所以不就是執(zhí)行call.call 并改變 call.call的上下文
我們來擼一遍call的源碼,
第一個(gè)參數(shù)是上下文, 當(dāng)我們call(null),this指向了window 當(dāng)我們傳入字符串 會(huì)把字符串包裝成對(duì)象
a.call 執(zhí)行 this是指向a的(誰(shuí)調(diào)用this 指向誰(shuí)) 然后又執(zhí)行了a方法,所以內(nèi)部是
Function.prototype.call = function(context){ context = context ? Object(context):window this() // 因?yàn)檎{(diào)用的都是函數(shù) 所以this是一個(gè)函數(shù) 也就是a }
那這樣并未改變this指向啊,咋辦? 上句話不是說((誰(shuí)調(diào)用this 指向誰(shuí))),所以我們要在內(nèi)部改變掉this,做如下修改
Function.prototype.call = function(context){ context = context ? Object(context):window context.fn = this context.fn() // 通過調(diào)用context.fn 來改變調(diào)用者 實(shí)現(xiàn)fn的this指向context 即改變a內(nèi)部的this }
那么參數(shù)怎么傳呢,我們首先要拿到call的里的參數(shù)
Function.prototype.call = function(context,...args){ context = context ? Object(context):window context.fn = this let r = context.fn(...args) // 通過調(diào)用context.fn 來改變調(diào)用者 實(shí)現(xiàn)fn的this指向context 即改變a內(nèi)部的this delete context.fn //刪除屬性 return r // 返回執(zhí)行的結(jié)果 }
現(xiàn)在我們回頭分析一下a.call.call.call(b,"b")
a.call.call是個(gè)函數(shù),它調(diào)用call方法 執(zhí)行它 我們進(jìn)入函數(shù)里面看看
首先把context 也就是b轉(zhuǎn)為字符串對(duì)象 它的屬性上賦予fn 也就是a.call.call ,然后執(zhí)行context.fn(...args), 也就是a.call.call("b") 接著刪除fn 返回執(zhí)行結(jié)果 宏觀來看 是a.call.call這個(gè)函數(shù)去執(zhí)行并傳入("b") a.call.call 也就是Function.prototype.call 所以就是call("b") 所以啊, 結(jié)果才是this是指向string的b 并且參數(shù)是undefined
Function.prototype.call = function(context,...args){ context = context ? Object(context):window context.fn = this //a.call.call("b") var r = context.fn(...args) // 通過調(diào)用context.fn 來改變調(diào)用者 實(shí)現(xiàn)fn的this指向context 即改變a內(nèi)部的this delete context.fn return r } function a(){ console.log(this,"a")}; function b(args){console.log("我是this:" + this,"我是b的參數(shù)args:" + args)} a.call.call.call(b,"我到底是參數(shù)呢還是this")
結(jié)論!
一個(gè)函數(shù)call2次或者2次以上 執(zhí)行的永遠(yuǎn)是b(b需要是一個(gè)函數(shù)), 并且call的第二個(gè)參數(shù)成為當(dāng)前context
apply 就是參數(shù)不同 直接上代碼
Function.prototype.apply = function(context,...args){ context = context ? Object(context):window context.fn = this; var r; if(args.length){ r = context.fn(...args) delete context.fn }else{ r = context.fn() } return r } function a(args){ console.log(this,args)}; function b(){console.log("我是this:" + this)} a.apply(b,[1,2,3,4])
bind 明天寫 累了
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/101838.html
摘要:也就是說當(dāng)返回的函數(shù)作為構(gòu)造函數(shù)的時(shí)候,時(shí)指定的值會(huì)失效,但傳入的參數(shù)依然生效。構(gòu)造函數(shù)效果的優(yōu)化實(shí)現(xiàn)但是在這個(gè)寫法中,我們直接將,我們直接修改的時(shí)候,也會(huì)直接修改函數(shù)的。 JavaScript深入系列第十一篇,通過bind函數(shù)的模擬實(shí)現(xiàn),帶大家真正了解bind的特性 bind 一句話介紹 bind: bind() 方法會(huì)創(chuàng)建一個(gè)新函數(shù)。當(dāng)這個(gè)新函數(shù)被調(diào)用時(shí),bind() 的第一個(gè)參數(shù)...
摘要:和概覽我們要將歸為一類,單獨(dú)歸為一類三者的共同點(diǎn)是都可以指定和都是綁定在的原型上的,所以的實(shí)例都可以調(diào)用這三個(gè)方法至于為什么,看完這篇文章你就懂了如果你不懂什么是實(shí)例的話,請(qǐng)移步深入淺出面向?qū)ο蠛驮透拍钇钊霚\出面向?qū)ο蠛驮透拍钇谝粋€(gè) 1.call/apply和bind概覽 我們要將call/apply歸為一類,bind單獨(dú)歸為一類 三者的共同點(diǎn)是都可以指定this call/...
摘要:三個(gè)方法的作用,都是改變的指向,只是用法稍微有些區(qū)別什么是既不指向函數(shù)自身,也不指函數(shù)的詞法作用域。它在函數(shù)定義的時(shí)候是確定不了的在函數(shù)被調(diào)用時(shí)才發(fā)生的綁定,也就是說具體指向什么,取決于你是怎么調(diào)用的函數(shù)。 1.排序法 思路:給數(shù)組先排序(由大到小排序),第一項(xiàng)就是最大值 let arr = [1,5,6,7,9,20,40,2,3]; let max1 = arr.sort(func...
摘要:文章盡量使用大量實(shí)例進(jìn)行講解,它們的使用場(chǎng)景。在嚴(yán)格模式下,函數(shù)被調(diào)用后,里面的默認(rèn)是后面通過調(diào)用函數(shù)上的和方法,該變指向,函數(shù)里面的指向。利用,可以傳入外層的上下文。同樣適用的還有,里面的對(duì)象,它也是一種類數(shù)組對(duì)象。 call,apply and bind in JavaScript 在ECMAScript中,每個(gè)函數(shù)都包含兩個(gè)繼承而來的方法:apply() 和 call(),這兩個(gè)...
摘要:深入系列第十篇,通過和的模擬實(shí)現(xiàn),帶你揭開和改變的真相一句話介紹方法在使用一個(gè)指定的值和若干個(gè)指定的參數(shù)值的前提下調(diào)用某個(gè)函數(shù)或方法。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,?qǐng)務(wù)必給予指正,十分感謝。 JavaScript深入系列第十篇,通過call和apply的模擬實(shí)現(xiàn),帶你揭開call和apply改變this的真相 call 一句話介紹 call: call() 方法在使用一個(gè)指定的 this...
閱讀 2085·2021-11-24 10:45
閱讀 1531·2021-11-18 13:15
閱讀 4695·2021-09-22 15:47
閱讀 4098·2021-09-09 11:36
閱讀 2071·2019-08-30 15:44
閱讀 3154·2019-08-29 13:05
閱讀 2561·2019-08-29 12:54
閱讀 2067·2019-08-26 13:47