JS基础知识整理[bind+call+apply]实现(三)

813 阅读4分钟

bind 定义

来源于mdn

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

输入

fn.bind(thisArg,arg1,arg2,...)
  • 第一个参数为绑定的this指向。
  • 其余的参数为。当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。

输出

返回一个原函数的拷贝,并拥有指定的this值和初始参数。

测试

  • 一个函数(原函数,他里的this会被改变)
  • 一个对象 (this指向的目标对象)

bind实现-方法一(es6版)

  • 第一步,保存原调用函数this。
  • 参数的截取,不多说了
  • 返回一个函数,这是bind的特性。
  • 返回函数中通过apply调用,做一个父函数,子函数的参数连接即可。
  • 为何要连接参数,是因为,调用的时候,参数传给第一个函数和返回函数都可以。
Function.prototype.myBind=function(){
	var me = this; // 保存原调用函数
	var args=[...arguments];
	var context = args.shift();
	return function(){
		//console.log(context,args,arguments);
		me.apply(context,[...args,...arguments])
	};
};
function A(x,y){
	console.log(this.b+" "+x+" "+y);
	//return this.b+" "+x+" "+y;
};
var B={b:1};
A.myBind(B,2)(3);//1 2 3

bind实现-方法一(es5版)

些方法特点是,多处借用Array原型上的方法处理伪数组arguments。

Function.prototype.myBind=function(){
	var me = this; // 保存原调用函数
    // 取改变后的this
	var context = Array.prototype.shift.call(arguments);	
	// 取第一个参数外的剩余参数,把arguments转为数组
	var args = Array.prototype.slice.call(arguments);
	// bind的特点返回一个函数
	return function(){
		var args2 = Array.prototype.slice.call(arguments);
		//参数拼接
		var allArgs = Array.prototype.concat.call(args,args2);
		me.apply(context,allArgs);
	}
};
function A(x,y){
	console.log(this.b+" "+x+" "+y);
	//return this.b+" "+x+" "+y;
};
var B={b:1};
A.myBind(B,2)(3); // 1 2 3

小提示

在arguments的处理上。call或者apply是用来改变函数执行是this指向的,这里以argumens对象为this来执行Array.prototype.slice函数,而Array.prototype.slice函数不带参数时默认返回的是数组对象本身。

Array.prototype.shift.call(arguments);和arguments[0]的功能看上去是一样的。但是shift改变了原始数据。所以,更方便。不过现在都用...了

slice()不传参数的复制功能很常用。

var a=[1,2,3];
var b = a.slice();
b;//[1, 2, 3]
a==b;//false

bind 小结

你调用我,我不一定会执行。

  • bind 函数的特点是:你调用我,我不直接执行,而是间接在函数内部在调用自己而进行执行。
  • 试想,如果,bind 中不进行原函数的调用。那么,bind的执行。可以什么也不做。但是bind的功能就是调用的时候,改变this。还是你调用他的原函数。然后把this,指向他的第一个参数。
  • 试想,函数A的调用。可能就是函数B的调用。可能就是函数B和C的调用。可能调用了什么也没做。什么也没返回。这就是函数。一个伟大的发明。

call的定义,输入输出

call() 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法

输入

输出

实现一(对象属性赋值this。调用这个对象的属性)

Function.prototype.myCall = function(obj){
	//console.log(obj);//改变的this指向,this指向A 然后obj.fn=A
	//console.log(A);// 原调用函数
	obj.fn = this;// 改变this指向为obj。此时obj.fn就是函数A
	obj.fn([...arguments].slice(1));//改变this后,调用原函数A。
	delete obj.fn;// 不能改变obj。把增加的fn属性删除
};
function A(arr){
    console.log(this.b+arr[0]+arr[1])
	
};
var B={b:1};
A.myCall(B,2,3); //6

call实现小结

  • 无论是call,apply,bind,调用原函数。改变this指向。处理参数。就这三件事。
  • 上面的call方法 多打印一个undefined。后续我在看一下,今天先去实现脚手架。

apply的实现

与call不同的就是参数的处理上

Function.prototype.myApply = function(obj){
	//console.log(obj);//改变的this指向
	//console.log(A);// 原调用函数
	obj.fn = this;// 改变this指向为obj。
	obj.fn([...arguments[1]]);//改变this后,调用原函数。
	delete obj.fn;// 不能改变obj。把增加的fn属性删除
};
function A(x,y){
	console.log(this.b+" "+x+" "+y);
};
var B={b:1};
A.myApply(B,[2,3]); // 1 2 3
// 1 2,3 undefined

总结:

  • 改变this指向:可以将原调用函数作为参数第一个对象(改变的this指向)的属性
  • 参数不定长需要考虑,我们使用...,
  • 我看网上有eval的实现版本,哈哈