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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

call、apply和bind的原生实现

發布時間:2023/12/15 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 call、apply和bind的原生实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

因為關乎到了this指向的問題,call、apply和bind的用法可以說是老生常談了。這篇文章的主要作用是利用js原生方法對三個方法進行實現,升入了解其中的原理,對相關知識點有更好的掌握。github地址call、apply和bind的原生實現

call與apply

簡單介紹:call和apply方法都是使用一個指定的this值和對應的參數前提下調用某個函數或方法。區別則在于call是通過傳多個參數的方式,而apply則是傳入一個數組。
舉個例子:

var obj = {name: 'linxin' }function func(age, sex) {console.log(this.name,age,sex); }func.call(obj,12,'女'); // linxin 12 女 func.apply(obj, [18, '女']); //linxin 18 女

模擬實現

思路:在JavaScript中的this指向說到了:函數還可以作為某個對象的方法調用,這時this就指這個上級對象。也就是我們平時說的,誰調用,this就指向誰。所以實現的方法就是在傳入的對象中添加這么一個方法,然后再去執行這個方法。為了保持對象一直,在執行完之后再把這個對象給刪除了。是不是很簡單^-^。
初體驗

Function.prototype.newCall = function(context) {context.fn = this; // 通過this獲取call的函數context.fn();delete context.fn; } let foo = {value: 1 } function bar() {console.log(this.value); } bar.newCall (foo); // 1

這樣就完成了基礎版本的實現,但是如果說有傳參數呢?
所以我們可以進行優化一下,因為傳入的參數數量是不確定的,所以我們可以從Arguments對象中去獲取,這個比較簡單。問題是參數是不確定的,我們如何傳入到我們要執行的函數中去呢 ? 這里我們有兩種選擇:一種是通過eval拼接的方式,另一種就要用到es6了。
體驗升級(eval版本):

Function.prototype.newCall = function(context) {context.fn = this;var args = [];for(var i = 1, len = arguments.length; i < len; i++) {args.push('arguments[' + i + ']');}eval('context.fn(' + args +')');delete context.fn; } let person = {name: 'Abiel' } function sayHi(age,sex) {console.log(this.name, age, sex); } sayHi.newCall (person, 25, '男'); // Abiel 25 男

體驗升級(ES6版本):

Function.prototype.newCall = function(context) {context.fn = this; context.fn(...Array.from(arguments).slice(1));delete context.fn; } let person = {name: 'Abiel' } function sayHi(age,sex) {console.log(this.name, age, sex); } sayHi.newCall (person, 25, '男'); // Abiel 25 男

讓然ES6的方法還可以不用到arguments就能實現
ES6版本再升級:

Function.prototype.newCall = function(context, ...parameter) {context.fn = this; context.fn(...parameter);delete context.fn; } let person = {name: 'Abiel' } function sayHi(age,sex) {console.log(this.name, age, sex); } sayHi.newCall (person, 25, '男'); // Abiel 25 男

這樣我們基本上實現了call的功能,但是還是存在一些隱患和區別。
當對象本身就有fn這個方法的時候,就有大問題了。
當call傳入的對象是null的時候,或者其他一些類型的時候,函數會報錯。
終極體驗:

Function.prototype.newCall = function(context, ...parameter) {if (typeof context === 'object') {context = context || window} else {context = Object.create(null)}let fn = Symbol()context[fn] = thiscontext[fn](...parameter);delete context[fn] } let person = {name: 'Abiel' } function sayHi(age,sex) {console.log(this.name, age, sex); } sayHi.newCall (person, 25, '男'); // Abiel 25 男

實現了call之后,apply也是同樣的思路。
apply實現:

Function.prototype.newApply = function(context, parameter) {if (typeof context === 'object') {context = context || window} else {context = Object.create(null)}let fn = Symbol()context[fn] = thiscontext[fn](parameter);delete context[fn] }

bind

bind也是函數的方法,作用也是改變this執行,同時也是能傳多個參數。與call和apply不同的是bind方法不會立即執行,而是返回一個改變上下文this指向后的函數,原函數并沒有被改變。并且如果函數本身是一個綁定了 this 對象的函數,那 apply 和 call 不會像預期那樣執行。
初體驗:

Function.prototype.bind = function (context) {var me = thisreturn function () { // bind之后得到的函數return me.call(context) // 執行是改變this執行} }

加入參數:

Function.prototype.bind = function (context,...innerArgs) {var me = thisreturn function (...finnalyArgs) {return me.call(context,...innerArgs,...finnalyArgs)} } let person = {name: 'Abiel' } function sayHi(age,sex) {console.log(this.name, age, sex); } let personSayHi = sayHi.bind(person, 25) personSayHi('男')

總結

以上是生活随笔為你收集整理的call、apply和bind的原生实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。