通俗易懂之JavaScript手动实现call方法

通俗易懂之JavaScript手动实现call方法

📖明白call方法作用,并据此梳理脉络

  • call方法作用:
    我们调用call方法的目的,即改变函数中this的指向。

  • 梳理脉络:

    • 前提:调用call方法的函数不能用箭头函数(ES6新增)来声明。这里并不是说箭头函数不能调用call方法,也可以调用,但是没有意义。因为箭头函数比较特殊,它的this在函数声明时就已经确定了,即函数声明时所处的对象,是无法被改变的。
      光说不练假把式,让代码说话:
    var name = 'Jack';
    var obj = {name:'Bob'};
    var showName = () => { // 用ES6箭头函数来声明
    	console.log(this.name);
    };
    var showName2 = function() { // ES5中函数声明方式
    	console.log(this.name);
    };
    showName.call(obj); // 输出'Jack'
    showName2.call(obj); // 输出'Bob'
    

    可见,箭头函数调用call方法是没有意义的,无法改变this的指向。

    • 手写思路:拿上述showName2函数举例。既然目的是改变this的指向,其实这里用改变是不准确的,因为函数声明时,this并未确定。要明白只有函数执行时,this才被确定(箭头函数除外~),所以这里用‘指定’比较好,即目的为指定函数中this的指向。 这里要把showName2函数中的this指向call方法传入的第一个参数obj,我们可以考虑给obj添加一个属性fn,把showName2函数赋值给它,通过obj.fn()方式调用,即可达到目的。
      光说不练假把式,让代码说话:
    Function.prototype.myCall = function(context){// 在Function构造函数的原型上添加我们自己的call方法:myCall
    	const content = context || window; /* 若有传参,则为context;若无传参,则为window。
    	例如showName2.myCall(obj),则content就指向obj */
    	const fn = Symbol(); // 这里用Symbol类型(ES6新增基本类型)声明一个变量,确保独一无二,作为接下来给content新添加属性的key
    	content[fn] = this; /* 这里的this,谁调用myCall方法,指的就是谁。
    	例如showName2.myCall(obj),执行完这行代码,即给obj新增了一个fn属性,值为showName2函数 */
    	const result = content.fn(...Array.from(arguments).slice(1)); /* 通过content.fn()方式调用方法,this被绑定为content即obj。
    	把参数传递进去就可以了,...是ES6的扩展运算符,Array.from()也是ES6语法,把类数组对象转为数组,因为第一个参数是this,所以把它剥掉 */
    	delete content[fn]; // 删除添加的临时属性
    	return result;
    }
    showName2.myCall(obj); // 输出'Bob'
    

    以上就完成了我们自己的call方法,其中有用到了ES6语法。如不想用ES6语法,可参照如下代码:

    	Function.prototype.myCall = function(context){
    	var content = context || window;
    	var fn = 'fn'+Math.random();
    	while(o1.hasOwnProperty(fn)){
    		fn = 'fn'+Math.random();
    	}
    	content[fn] = this; 
    	var args = [];
    	for(var i=1,length=arguments.length;i<length;i++){
    		args.push('arguments['+i+']');
    	}
    	var result = eval('content.fn('+args+')');/* eval函数把字符串解析为js代码来执行,所以上面在args中push字符串格式 */
    	delete content[fn];
    	return result;
    }
    showName2.myCall(obj); // 输出'Bob'
    

    至此结束,与诸君共勉~

    🐱传送门:通俗易懂之JavaScript手动实现apply方法

    🐱传送门:通俗易懂之JavaScript手动实现bind方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值