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