call
call() 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法
例子:
let foo = {
value: 1
};
function bar() {
console.log(this.value);
}
bar.call(foo); // 1
注意两点:
1、call 改变了this的指向,指到了foo
2、bar 函数执行了
模拟实现第一步
试想当调用 call 的时候,把foo 对象改造成如下:
let foo = {
value: 1,
bar: function() {
console.log(this.value);
}
}
foo.bar(); // 1
这个时候this就指向了 foo,
但却给foo对象增加了一个属性,
我们使用delete再删除掉它不就好了
所以模拟的步骤可以分为:
1、将函数设为对象的属性
2、执行该函数
3、删除该函数
// 第一版
Function.prototype.call2 = function(context){
// 首先获取调用call的函数,用this可以获取
context.fn = this;
context.fn();
delete context.fn;
}
// 测试一下
let foo = {
value: 1
};
function bar(){
console.log(this.value);
}
bar.call2(foo); // 1
模拟实现第二步
call 函数给定参数执行函数,但传入参数并不确定, 我们可以从 Arguments 对象中取值,取第二个到最后一个值,放到一个数组里
// 第二版
Function.prototype.call2 = function(context){
context.fn = this;
let args = [];
for(var i = 1; i < arguments.length; i ++){
args.push(arguments[i]);
}
context.fn(... args); // ES6解构数组
delete context.fn;
}
// 测试一下
let foo = {
value: 1
};
function bar(name,age){
console.log(name); // cyl
console.log(age); // 18
console.log(this.value); // 1
}
bar.call2(foo,'cyl',18);
模拟实现第三步
有两小点需要注意:
1、this参数可以传 null,当为 null 时,视为指向 window
2、函数可以有返回值的
// 第三版
Function.prototype.call2 = function(context){
var context = context || window;
context.fn = this;
let args = [];
for(var i = 1,len = arguments.length; i < len; i ++){
args.push(arguments[i]);
}
let result = context.fn(... args);
delete context.fn;
return result;
}
// 测试一下
// 注意全局这里使用let声明时,通过window获取value为undefined,let声明不属于window
var value = 2;
let obj = {
value: 1
}
function bar(name,age){
console.log(this.value);
return {
value: this.value,
name: name,
age: age
}
}
bar.call2(null); // 2
console.log(bar.call2(obj,'cyl',18));
// 1
// Object {
// value: 1,
// name: cyl,
// age: 18
// }
apply
apply 的实现跟 call 类似,区别在于call是序列化传参,apply传参时传递的是一个数组
Function.prototype.apply2 = function(context,arr){
var context = Object(context) || window;
context.fn = this;
var result;
if(!arr){
result = context.fn();
}else{
result = context.fn(... arr); // apply第二参数为数组,无需使用arguments
}
delete context.fn;
return result;
}
网友评论