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));
}
}
}
参考链接: