持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
手写call
1.call用法
var obj ={name:'lucky'}
function fn(a,b){
console.log(this,a+b) //obj,3
}
fn.call(obj,1,2)
2. 手写call
分析
- 通过原型链我们知道调用call的肯定是函数
- 执行当前的函数
- 改变this指向
1.通过这三句就能写出核心代码(简易)
//首先在函数拓展出一个手写call方法
Function.prototype.myCall = function(context){
//改变this指向
/**
1.this就是fn1函数
2.context.fn = this 相当于把fn1函数的地址赋值给context.fn的一个随意属性
3.context.fn()就相当于把this指向了传进来的值context
核心:把this(fn1)变成context(调用者)的一个方法,那么fn1的调用自然就变成了
context的调用达到了改变this指向的作用
**/
context.fn = this
context.fn();
//调用完删除拓展属性
delete context.fn
}
var obj ={name:'lucky'}
function fn1(a,b){
console.log(this) //obj
}
fn1.myCall(obj)
2. 完整写法
- 因为call方法会给调用者自动包装类型,比如null、undefined、String、number的调用,但是我们自己写的方法就需要做判断了。
var obj ={name:'lucky'}
function fn(a,b){
console.log(this,a+b) //obj,3
}
fn.call(null,1,2) //window
fn.call(undefined,1,2) //window
fn.call(true,1,2) //Boolean
fn.call(1,1,2) //Number
fn.call('1',1,2) //String
- 考虑参数的处理 通过eval处理参数
var arr = [2, 3, 4, 5];
console.log(arr.toString())
function fn() {
console.log(arguments);
}
// fn("2,3,4,5")
//eval可以把字符串转换成正常代码运行,所以只需要拼接'fn(1,2,3,4)'这样的字符串即可
eval("fn(1,2,3,4)")
- 最后是完整写法
Function.prototype.myCall = function (context) {
var type = typeof context;
//判断改变后的上下文对象是null和undefined的时候 this应该指向window
if (context === null || context === undefined) {
context = window;
}
//如果改变后的上下文对象是基本包装类型,则this指向其包装对象
switch (type) {
case "number":
context = new Number(context);
break;
case "boolean":
context = new Boolean(context);
break;
case "string":
context = new String(context);
break;
}
//获取第二个以后的参数,就是fn的参数
var arg = Array.from(arguments).slice(1);
/**
梳理:
1.fn1.myCall调用,所以这里的this指向的就是fn1,
给context扩展一个方法,这个方法就是fn1:context[key] = this;
2.context就是改变之后的上下文对象
3.然后调用context的扩展的这个方法,fn1就会被调用,并且this指向了context
**/
//给context扩展的方法名要是一个独一无二的值,防止覆盖原有方法
var key = Date.now().toString(36);
context[key] = this;
//然后调用context的扩展的这个方法,fn1就会被调用,并且this指向了context
var result = eval("context[key](" + arg.toString() + ")");
//此时改变之后的上下文对象context就会多一个方法,使用完成之后要删除掉这个方法
delete context[key];
return result;
}
var obj = {
name: "lucky",
fn: function () {
console.log("hello")
}
}
function fn1(a, b) {
console.log(this, a + b)
return "123";
}
console.log(fn1.call(obj, 1, 2));
fn1.myCall(obj, 1, 2);
fn1.myCall(null, 1, 2);
fn1.myCall(undefined, 1, 2);
fn1.myCall(1, 1, 2);
fn1.myCall("str", 1, 2);
fn1.myCall(true, 1, 2);
验证结果
好了,以上就是本篇文章的分享,感谢阅读!