call、bind、apply知識點
apply
function.apply(obj, [param1,params2,...]) // obj:要綁定的this // 第二個參數:類數組或數組,做爲function的參數傳入 // 當即執行
call
function.call(obj, param1, param2, ...) // obj:要綁定的this // 第二個參數:函數運行的參數,用逗號隔開 // 當即執行
bind
function.bind(obj, param1, param2, ...) // obj:要綁定的this // 第二個參數:函數運行的參數,用逗號隔開 // 返回一個函數
基本理念:借用方法,修改this
指向javascript
const params = 'ahwgs' const toString = Object.prototype.toString const type = toString.call(params) console.log('數據類型',type) // [object String]
var arrayLike = { 0: 'OB', 1: 'Koro1', length: 2 } Array.prototype.push.call(arrayLike, '添加元素1', '添加元素2'); console.log(arrayLike) // {"0":"OB","1":"Koro1","2":"添加元素1","3":"添加元素2","length":4}
借用數組的push方法,向arrayLike
中push
新數據html
call
實現Function.prototype.myCall = function(context,...arr) { if (context === null || context === undefined) { // 指定爲 null 和 undefined 的 this 值會自動指向全局對象(瀏覽器中爲window) context = window } else { context = Object(context) // 值爲原始值(數字,字符串,布爾值)的 this 會指向該原始值的實例對象 } const specialPrototype = Symbol('特殊屬性Symbol') // 用於臨時儲存函數 context[specialPrototype] = this; // 函數的this指向隱式綁定到context上 let result = context[specialPrototype](...arr); // 經過隱式綁定執行函數並傳遞參數 delete context[specialPrototype]; // 刪除上下文對象的屬性 return result; // 返回函數執行結果 }
apply
Function.prototype.myApply = function (context) { if (context === null || context === undefined) { context = window // 指定爲 null 和 undefined 的 this 值會自動指向全局對象(瀏覽器中爲window) } else { context = Object(context) // 值爲原始值(數字,字符串,布爾值)的 this 會指向該原始值的實例對象 } // JavaScript權威指南判斷是否爲類數組對象 function isArrayLike(o) { if (o && // o不是null、undefined等 typeof o === 'object' && // o是對象 isFinite(o.length) && // o.length是有限數值 o.length >= 0 && // o.length爲非負值 o.length === Math.floor(o.length) && // o.length是整數 o.length < 4294967296) // o.length < 2^32 return true else return false } const specialPrototype = Symbol('特殊屬性Symbol') // 用於臨時儲存函數 context[specialPrototype] = this; // 隱式綁定this指向到context上 let args = arguments[1]; // 獲取參數數組 let result // 處理傳進來的第二個參數 if (args) { // 是否傳遞第二個參數 if (!Array.isArray(args) && !isArrayLike(args)) { throw new TypeError('myApply 第二個參數不爲數組而且不爲類數組對象拋出錯誤'); } else { args = Array.from(args) // 轉爲數組 result = context[specialPrototype](...args); // 執行函數並展開數組,傳遞函數參數 } } else { result = context[specialPrototype](); // 執行函數 } delete context[specialPrototype]; // 刪除上下文對象的屬性 return result; // 返回函數執行結果 };
bind
Function.prototype.myBind = function (objThis, ...params) { const thisFn = this; // 存儲源函數以及上方的params(函數參數) // 對返回的函數 secondParams 二次傳參 let fToBind = function (...secondParams) { const isNew = this instanceof fToBind // this是不是fToBind的實例 也就是返回的fToBind是否經過new調用 const context = isNew ? this : Object(objThis) // new調用就綁定到this上,不然就綁定到傳入的objThis上 return thisFn.call(context, ...params, ...secondParams); // 用call調用源函數綁定this的指向並傳遞參數,返回執行結果 }; if (thisFn.prototype) { // 複製源函數的prototype給fToBind 一些狀況下函數沒有prototype,好比箭頭函數 fToBind.prototype = Object.create(thisFn.prototype); } return fToBind; // 返回拷貝的函數 };