call、apply的实现原理
function fn(x, y) {
console.log('我想喝手磨咖啡' );
console.log(this);
console.log(x + y);
}
var obj={
name :'andy'
};
//1、将函数设置为对象的属性
obj.fn = fn
//2、执行这个函数
obj.fn()
//3、删除添加的这个属性
delete obj.fn
手写call方法
- 方法一
Function.prototype.newCall = function () {
//获取执行对象
var tmp = arguments[0] || window;
//获取函数的参数
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']');
}
//将函数设置为对象的属性
tmp.fn = this;
//使用eval方法执行函数,将函数的返回结果赋值给result
var result = eval('tmp.fn(' + args.join(",") + ')');
//删除为对象添加的fn属性
delete tmp.fn;
//返回返回结果
return result;
}
- 方法二
Function.prototype.mycall = function () {
// 获取调用对象
var tmp = arguments[0] || window;
// 获取参数
var args = [...arguments].slice(1)
//将函数设置为对象的属性
tmp.fn = this;
//调用这个函数,将返回结果赋值给result
var result = tmp.fn(...args)
//删除为对象添加的fn属性
delete tmp.fn;
//返回函数的执行结果
return result;
}
手写apply方法
Function.prototype.newApply = function () {
// 获取函数的调用对象
var tmp = arguments[0] || window;
// 获取参数数组
var args = arguments[1];
//将函数设置为对象的属性
tmp.fn = this;
//将函数的执行结果返回给result
var result = tmp.fn(...args);
//删除新添加的属性
delete tmp.fn;
//返回执行结果
return result;
}
手写bind方法
Function.prototype.newBind = function () {
// 获取函数的调用对象
var tmp = arguments[0] || window;
// 获取参数
var args = [...arguments].slice(1);
//返回执行函数
return () => {
//将函数设置为调用对象的属性
tmp.fn = this;
//调用这个函数,将返回值赋值给result
var result = tmp.fn(...args);
//删除新添加的属性
delete tmp.fn;
//返回结果
return result;
}
}
测试代码
// 手写call方法
// 法一
Function.prototype.newCall = function () {
var tmp = arguments[0] || window;
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push('arguments[' + i + ']');
}
tmp.fn = this;
var result = eval('tmp.fn(' + args.join(",") + ')');
// eval('tmp.fn(' + args.join(",") + ')');
delete tmp.fn;
return result;
}
//方法二
Function.prototype.mycall = function () {
// 获取调用对象
var tmp = arguments[0] || window;
// 获取参数
var args = [...arguments].slice(1)
tmp.fn = this;
var result = tmp.fn(...args)
delete tmp.fn;
return result;
}
// 手写apply
Function.prototype.newApply = function () {
// 获取函数的调用对象
var tmp = arguments[0] || window;
// 获取参数数组
var args = arguments[1];
tmp.fn = this;
var result = tmp.fn(...args);
delete tmp.fn;
return result;
}
//手写bind
Function.prototype.newBind = function () {
// 获取函数的调用对象
var tmp = arguments[0] || window;
// 获取参数
var args = [...arguments].slice(1);
return () => {
tmp.fn = this;
var result = tmp.fn(...args);
delete tmp.fn;
return result;
}
}
function fn(x, y) {
console.log('我想喝手磨咖啡' );
console.log(this);
console.log(x + y);
return {
x:x,
y:y,
}
}
var obj={
name :'andy'
};
console.log("-------------原理测试---------------");
//1、将函数设置为对象的属性
obj.fn = fn
//2、执行这个函数
obj.fn(1,2)
//3、删除添加的这个属性
delete obj.fn
console.log(obj);
console.log("-------------原理测试---------------");
console.log("-------------call-------------------");
fn.call(obj,1,2)
fn.newCall(obj,1,2)
fn.mycall(obj,1,2)
console.log(obj);
console.log("-------------call-------------------");
console.log("-------------apply------------------");
fn.apply(obj,[1,2])
fn.newApply(obj,[1,2])
console.log(obj);
console.log("-------------apply------------------");
console.log("-------------bind-------------------");
var a = fn.bind(obj,1,2)
console.log(a());
var b = fn.newBind(obj,1,2)
console.log(b());
console.log(obj);
console.log("-------------bind-------------------");
执行结果
-------------原理测试---------------
我想喝手磨咖啡
{name: "andy", fn: ƒ}
3
{name: "andy"}
-------------原理测试---------------
-------------call-------------------
我想喝手磨咖啡
{name: "andy"}
3
{x: 1, y: 2}
我想喝手磨咖啡
{name: "andy", fn: ƒ}
3
{x: 1, y: 2}
我想喝手磨咖啡
{name: "andy", fn: ƒ}
3
{x: 1, y: 2}
{name: "andy"}
-------------call-------------------
-------------apply------------------
我想喝手磨咖啡
{name: "andy"}
3
{x: 1, y: 2}
我想喝手磨咖啡
{name: "andy", fn: ƒ}
3
{x: 1, y: 2}
{name: "andy"}
-------------apply------------------
-------------bind-------------------
我想喝手磨咖啡
{name: "andy"}
3
{x: 1, y: 2}
我想喝手磨咖啡
{name: "andy", fn: ƒ}
3
{x: 1, y: 2}
{name: "andy"}
-------------bind-------------------