JavaScript中改变context上下文的方法

序言:

        作为一名合格的前端开发者,大家都应该知道改变js作用域中上下文的方法有:call、apply和bind。思考一个问题:还有没有更好的实现方式呢?

1、call和apply

call和apply是最简单实现改变函数体内部this指向的方法,他们的区别仅仅是第二个参数不同。语法示例:

obj.call(thisObj,arg1,agr2,...)
obj.apply(thisObj,[arg1,agr2])

代码示例(Math.max)

Math.max(1, 3, 2)

 如输入参数是数组呢?

Math.max.apply(null,[1,2,3,4,2,3])

说明:上面示例代码中,第一个参数为null,也可以为其他(空字符串,对象),仅仅是“借用”Math的max方法而已。

2、bind

bind方法是创建一个新方法,当函数调用时将this设置为提供的值。与call类似,除第一个参数外是可变参数,语法示例:

obj.bind(thisObj,arg1,agr2,...)

这时thisObj就有了obj方法和属性。

bind与call和apply不同的是,bind之后返回一个函数,不会立即执行。需要再显示执行一次才能完成函数的调用。如:

let m = test.bind(obj,3)
m()

另外,bind也常用在ES6的Class绑定上下文。

class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    this.p().then(this.say);
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say(str) {
    console.log(this);
    console.log(this.name + str);
  }
}

let dog = new Dog();
dog.start();

上述代码会显示:

 即在Promise的then方法参数是一个匿名函数,匿名函数的this指向是:undefined。

这里有2种方案:

(1)箭头函数

class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    this.p().then(this.say);
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say= (str) => {
    console.log(this);
    console.log(this.name + str);
  }
}

let dog = new Dog();
dog.start();

 即,使用箭头函数,this执行函数定义时作用域,即Dog对象

(2)使用bind绑定this指向

class Dog {
  constructor() {
    this.name = 'adong';
  }

  start() {
    this.p().then(this.say.bind(this));
  }

  p() {
    return new Promise((resolve, reject)=>{
      resolve('good');
    })
  }
  
  say(str) {
    console.log(this);
    console.log(this.name + str);
  }
}

let dog = new Dog();
dog.start();

3、使用ES7的Decorators

使用autobind-decorator库,实现自动this绑定。

import autobind from 'autobind-decorator'
class MathTest {
    constructor(val) {
        this.val = val
    }
    @autobind
    show() {
        return this.val
    }
}
let mathTest = new mathTest(42);
let show = mathTest.show;
show()

 当然@autobind也可以在整个类上进行this上下文的绑定。

4、双冒号运算符

双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

示例代码:

[1,2,3]::Array.prototype.map(x=>{return x*3})

经过babel编译后:

"use strict";

var _context;

(_context = [1, 2, 3], Array.prototype.map).call(_context, function (x) {
  return x * 3;
});

即对象[1,2,3]作为this绑定到了Array的map方法上。

5、总结

以上即是js中绑定this上下文的方法,助力源码阅读。

原文地址:https://www.cnblogs.com/mengfangui/p/12380954.html