Javascript模擬實現call、apply、bind
阿新 • • 發佈:2019-02-20
var foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
類似於
var foo = {
value: 1,
bar: function () {
console.log(this.value);
}
}
foo.bar() // 1
Javascript模擬實現call可以分三步實現:
第一步模擬新增屬性方法
foo.fn = bar;
第二步呼叫方法
foo.fn()
第三步刪除屬性方法
delete foo.fn
ES3模擬實現call
Function.prototype.call = function (context) { // 如果context是null,作用域就是window context = context || window; // 新增方法 context.fn = this; var args = []; // 下面沒有直接把arguments[i]push給args,是因為eval會先對args.toString(),toString後arguments[i]就變成了一個沒有宣告的變數,就會出錯 for (var i = 1; i < arguments.length; i++) { args.push('arguments[' + i +']'); } // args = ['arguments[1]', arguments['2'],....]; // 呼叫方法 var result = eval('context.fn(' + args + ')'); // 刪除方法 delete context.fn; return result; }
ES6模擬實現call
Function.prototype.call = function (context, ...args) {
context = context || window;
let fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
Reflect.deleteProperty(context, fn);
return result;
}
ES3模擬實現apply:
apply與call基本相同,區別在於apply引數的是陣列
Function.prototype.apply = function (context, arr) { context = context || window; context.fn = this; var args = []; for (var i = 0; i < arr.length; i++) { args.push('arr[' + i + ']'); } var result = eval('context.fn(' + args + ')'); delete context.fn; return result; }
ES6模擬實現apply
Function.prototype,apply = function (context, arr) {
context = context || window;
let fn = Symbol();
context[fn] = this;
const result = context[fn](...arr);
Reflect.deleteProperty(context, fn);
return result;
}
bind和call、apply不同點是:
一、留住this
二、返回一個函式
ES3模擬實現bind
Function.prototype.bind = function (context) { if (typeof this !== 'function') { throw new Error('bound is not callable') } // 留住this var selt = this; // arguments轉陣列,並從index=1擷取 var args = Array.prototype.slice.call(arguments, 1); var fNop = function () {}; var fBound = function () { var boundArgs = Array.prototype.slice.call(arguments); return self.apply(this instanceof fNop ? this : context, args.concat(boundArgs)); } // 原型鏈繼承 fNop.prototype = this.prototype; fBound.prototype = new fNop(); return fBound; }
ES6模擬實現bind
if (typeof Function.protorype.bind !== 'function') {
Function.prototype.bind = function (context, ...test) {
if (typeof this !== 'function') {
throw new Error('bound is not callable');
}
var self = this;
return function F(...args) {
if (this instanceof F) {
return new self(...test, ...args);
}
return self.apply(context, test.concat(args));
}
}
}
參考連結: