js关于call,apply,bind方法的使用与实现

101 阅读3分钟

call:

先看使用方法

var obj = {
    name: "小明"
   }
var name = "小红"	
function print(sex) {
	console.log(this.name)
        console.log(this)
        console.log(sex)
}
print('女');//小红,window,女。如果严格模式下this会是undefind,所以会报错
print.call(obj,'男');//小明,obj,男

可以看到this的值已经被改变了。在没使用call之前指向的是window(因为是非严格模式,默认指向window)。 下面尝试自己实现这个功能:

Function.prototype.myCall = function() {
    //判断调用此方法的是不是一个函数,不是的话就抛出错误
    if (typeof this !== 'function') {
    	throw new TypeError('请用函数调用')
    };
    //然后获取传入的需要改变指向的this对象。
    var args=[...arguments];//这里使用了es6的语法
    var context =args.shift() || window;
    //将当前函数挂载到传入的对象上
    var fn = Symbol('fn'); // 我们声明一个独一无二的属性
    context[fn] = this;
    //执行函数
    var res = context[fn](...args);
    //因为传入的对象上没有fn这个函数,所以执行完了需要删掉
    delete context[fn];
    //返回执行结果
    return res;
    }

接下来试试我们自己实现的call

var obj = {
	name: "小明"
}
var name = "小红"

function print(sex) {
	console.log(this.name)
        console.log(this)
        console.log(sex)
}
print('女');//小红,window,女。
print.myCall(obj,'男');//小明,obj,男

apply

apply的使用方法与call其实是一样的。但是区别在于传参的时候,传的是一个数组

var obj = {
    name: "小明"
   }
var name = "小红"	
function print(sex) {
	console.log(this.name)
        console.log(this)
        console.log(sex)
}
print('女');//小红,window,女。
print.apply(obj,['男']);//小明,obj,男

接下来我们自己实现:

Function.prototype.myApply=function(){
  if (typeof this !== 'function') {
  	throw new TypeError('请传入一个函数')
  };
  var args = [...arguments]; 
  var context = args.shift() || window;
  var fn = Symbol('fn'); 
  context[fn] = this;
  var res = context[fn](...args[0]);//这里就是和call不一样的地方,因为args[0]就是传入的参数数组
  delete context[fn];
  return res;
}

使用自己实现的apply:

var obj = {
  	name: "小明"
  }
  var name = "小红"
  function print(sex) {
	console.log(this.name)
        console.log(this)
        console.log(sex)
  }
print('女');//小红,window,女。
print.myApply(obj,['男']);//小明,obj,男

bind

bind方法的作用也是改变this的指向。但是与call和apply有不一样的地方,此方法返回的是一个函数,不会立即执行,需要我们自己去执行。并且可以分两次传参。使用方法如下:

var obj = {
  	name: "小明"
  }
  var name = "小红"
  function print(age, sex) {
  	console.log(this.name)
  	console.log(this)
  	console.log(age)
  	console.log(sex)
  }
  print(20,'女') //小红,window,20,女
  var bindPrint = print.bind(obj,18)
  bindPrint("男") //小明,obj,18,男

可以看到this的指向已经变了。并且传参可以分次或者一次性传完。接下来我们试试自己实现这个方法:

Function.prototype.myBind = function() {
 var self = this; //将函数存起来
 //关于call和apply的使用与自己实现,上面我们已经实现过了。这里就不再重复相关的过程。直接使用
 var context = [].shift.call(arguments); //获取传入的this
 var args = [].slice.call(arguments) //剩余的参数转为数组
 return function() { //返回一个新的函数.需要再次调用一次改变this后的函数
   var args2 = [].slice.call(arguments)//这里将第二次的参数保存起来
   return self.apply(context, args.concat(args2))//返回函数执行的结果
 }
}

运行自己实现的bind方法:

var obj = {
  	name: "小明"
  }
  var name = "小红"
  function print(age, sex) {
  	console.log(this.name)
  	console.log(this)
  	console.log(age)
  	console.log(sex)
  }
  print(20,'女') //小红,window,20,女
  var bindPrint = print.myBind(obj,18)
  bindPrint("男") //小明,obj,18,男

以上