改变函数内部this指针的指向函数(bind,apply,call)

今晚说一下改变this指向的指向函数。

一.改变函数内部this指针的指向函数

  • 通过applycall改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象;第二个是传入的参数,apply是数组,而call则是arg1,arg2…这种形式。
  • 通过bind改变this作用域会返回一个新的函数(我理解的是bind不改变原函数,再var一个新的函数拿来用。),这个函数不会马上执行。call 是把第二个及以后的参数作为 func 方法的实参传进去,而 func1 方法的实参实则是在 bind 中参数的基础上再往后排
function func(a, b, c) {
    console.log(a, b, c);
}
var func1 = func.bind(null,'linxin');//重新命名
func('A', 'B', 'C');    // A B C

//参数从bind的第二个参数插入到新函数fun1的第一个参数之前
func1('A', 'B', 'C');  // linxin A B

func1('B', 'C');       // linxin B C

func.call(null, 'linxin');      // linxin undefined undefined

二.箭头函数中this指向举例

var a=11;
function test2(){
	this.a=22;
	let b=()=>{console.log(this.a)}
    b();
       			 }
       			 
var x=new test2();
   //输出22定义时绑定

三.如何实现一个 bind,apply,call函数

对于实现以下几个函数,可以从几个方面思考

  • 不传入第一个参数,那么默认为 window
  • 改变了 this 指向,让新的对象可以执行该函数。那么思路是否可以变成给新的对象添加一个函数,然后在执行完以后删除?

1.bind:

  • fun.bind(thisArg[, arg1[, arg2[, …]]])
  • 他是直接改变这个函数的this指向并且返回一个新的函数,之后再次调用这个函数的时候this都是指向bind绑定的第一个参数。bind传餐方式跟call方法一致。
  • thisArg 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。
  • arg1, arg2, … 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
Function.prototype.myBind = function (context) {
	if (typeof this !== 'function') {
	throw new TypeError('Error')
             }
	var _this = this
	var args = [...arguments].slice(1)
    // 返回一个函数
	return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
        return new _this(...args, ...arguments)
                    }
	return _this.apply(context, args.concat(...arguments))
                  }

2.call:

  • fun.call(thisArg, arg1, arg2, …)
  • call跟apply的用法几乎一样,唯一的不同就是传递的参数不同,call只能一个参数一个参数的传入。
  • thisArg: 在fun函数运行时指定的this值。需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
  • arg1, arg2, … 指定的参数列表
Function.prototype.myCall = function (context) {
    var context = context || window
     // 给 context 添加一个属性
     // getValue.call(a, 'yck', '24') => a.fn = getValue
    context.fn = this
     // 将 context 后面的参数取出来
 var args = [...arguments].slice(1)
     // getValue.call(a, 'yck', '24') => a.fn('yck', '24')
 var result = context.fn(...args)
      // 删除 fn
      delete context.fn
      return result
           }
                

3.apply

  • apply则只支持传入一个数组,哪怕是一个参数也要是数组形式。最终调用函数时候这个数组会拆成一个个参数分别传入。
  • thisArg 在 fun 函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
  • argsArray 一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 fun 函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
   Function.prototype.myApply = function (context) {
                  var context = context || window
                  context.fn = this
                
                  var result
                  // 需要判断是否存储第二个参数
                  // 如果存在,就将第二个参数展开
                  if (arguments[1]) {
                    result = context.fn(...arguments[1])
                  } else {
                    result = context.fn()
                  }
                
                  delete context.fn
                  return result
                }

四.总结

  • 当我们使用一个函数需要改变this指向的时候才会用到callapplybind
  • 如果你要传递的参数不多,则可以使用fn.call(thisObj, arg1, arg2 …)
  • 如果你要传递的参数很多,则可以用数组将参数整理好调用fn.apply(thisObj, [arg1, arg2 …])
  • 如果你想生成一个新的函数长期绑定某个函数给某个对象使用,则可以使用const newFn = fn.bind(thisObj); newFn(arg1, arg2…)
  • call和apply第一个参数为null/undefined,函数this指向全局对象,在浏览器中是window,在node中是global

this指针问题没有说,我也有些模糊,找时间总结一下。
再见!

你可能感兴趣的:(this)