唯心主义蠢货的[js知识总结] call apply bind改变this指向

200 阅读2分钟

手撸bind apply call 改变函数的this指向


call.(obj,arg1,arg2,arg3...)

call的用法:

首先传入一个对象,再传入对应的参数进行解构赋值,返回函数结果。

错误情况:call中没有传入参数,则默认obj为window

代码实现

  1. 函数调用.call来改变内部的this指向,所以我们可以在Function.prototype中再新增添一个方法作为我们自己的call
var value = 3;
var obj = {
	value:4
}
function test(  ) {
	console.log(this.value);
}
Function.prototype.newCall = function (  ) {
    console.log(this);
}
test.newCall(obj); // test
  1. 我们发现此时输出的this即为当前被调用的函数,所以如果我们在这个对象上添加一个fn属性,然后把函数赋给这个属性,然后调用这个属性,则可以直接在内部改变this指向
var value = 3;
var obj = {
	value:4
}
function test(  ) {
	console.log(this.value);
}
Function.prototype.newCall = function ( that ) {
	console.log(this);
	console.log(that);	
	that.fn = this;
	that.fn();
}
test.newCall(obj); // test  obj   4
  1. 再对这个函数进行完善,将添加到对象中的东西删除掉

    1. 考虑解构赋值的情况( ES6 的不定参数 ...args,在函数中args以数组形式存在, ...args为拓展参数)

      ...[ 2,3,6,"ss"] => 2 3 6 "ss"

    2. 考虑错误处理的情况,当非object时或者

    3. 考虑返回值情况(js的函数默认返回值为undefined)

var value = 3;
var obj = {
	value:4
}
function test( a,b,c ) {
	console.log(a+b+c);
	console.log(this.value)
}
Function.prototype.newCall = function ( that,...args ) {
    if(that.toString() !== "[object object]"){
    	throw that+" is not an Object";
    }
    that = that || window; // that为空(undefined null)  则为window
    that.fn = this;
    const result = that.fn(...args);
    delete that.fn;
    return result;
    }
m = test.newCall(obj,1,2,3); // 6 4
console.log(m); // undefined

apply.(obj,[arg])

apply的用法

apply在用法上和call基本相同,唯一不同的是apply中第二个参数为一个参数数组

Function.prototype.newApply = function( that , arg){
    if(that.toString() !== "[object object]"){
    	throw that+" is not an Object";
    }
    that = that || window;  // that为空(undefined null)  则为window
    that.fn = this;
    arg = arg || [];
    const result = that.fn(...arg);
    delete that.fn;
    return result;
}

bind.(obj,arg1,arg2,arg3...)

bind的参数同call相同,但是bind是返回一个改变this指向后的函数实例;

所以利用闭包返回一个匿名函数,内部调用这个新函数

bind需要实现两种形式的赋值

  • 类似于bind(context,arg1,arg2..)的解构赋值
  • 返回函数实例,再进行调用
Function.prototype.newBind = function ( that,...argsA ) {
    if(that.toString() !== "[object object]"){
    	throw that+" is not an Object";
    }
	that = that || window;
	const Fn = this;
	return function ( ...argsB ) {
		let args = argsB.length == 0 ? argsA : argsB; // 如果B不存在 传入的为A的参数
		return Fn.apply(that,args);
	};
}

Fn为当前函数,然后使用apply将that新指向传入,又因为args在函数中是以数组的形式存在,所以即可实现

参考