在 JavaScript 中解构对象时如何绑定方法?

How to bind methods when destructuring an object in JavaScript?

在 JavaScript 中解构对象时如何绑定方法?

const person = {
  getName: function() {
    console.log(this);
  }
};

var a = person.getName;
var b = person.getName.bind(person);
var {getName: c} = person;

person.getName(); //=> {getName: [Function]}
a();              //=> window or global
b();              //=> {getName: [Function]}
c();              //=> window or global

我希望 c 登录其 "parent" 对象 {getName: [Function]} 的控制台。

在一个 destructuring 行中解构对象时,有没有办法绑定所有方法?

不行,没办法。从对象中分离出来的函数失去了原来的上下文。在 JavaScript 中进行破坏没有语法来动态处理提取的值。

您可以使用 getter 或代理来绑定一个方法,只要您 get 它,甚至使用解构。

两种解决方案都通过使用 String.startsWith() 在名称的开头查找 bound 来检查方法是否已经绑定。如果未绑定,该方法将在返回之前被绑定。

  1. 使用 getter 将方法自动绑定到对象。每种方法都需要 getter

const person = {
  prop: 5,
  _getName: function() {
    console.log(this.prop);
  },
  
  get getName() {
    // if not bound, bind the method
    if(!this._getName.name.startsWith('bound ')) {
      this._getName = this._getName.bind(this);
    }
    
    return this._getName;
  }
};

var a = person.getName;
var b = person.getName.bind(person);
var {getName: c} = person;

person.getName(); //=> 5
a();              //=> 5
b();              //=> 5
c();              //=> 5

  1. 使用 proxy 将方法自动绑定到对象。为所有方法定义一次。

var handler = {
  get: function(target, prop, receiver) {
    // if method, and not bound, bind the method
    if(typeof target[prop] === 'function' && !target[prop].name.startsWith('bound ')) {
      target[prop] = target[prop].bind(target);
    }
    
    return target[prop];
  }
};

const person = new Proxy({
  prop: 5,
  getName: function() {
    console.log(this.prop);
  }
}, handler);

var a = person.getName;
var b = person.getName.bind(person);
var {getName: c} = person;

person.getName(); //=> 5
a();              //=> 5
b();              //=> 5
c();              //=> 5

有一个使用 ES6 classes 的简单解决方法。您可以在 class 构造函数中使用 bind 来手动设置函数的上下文。

在下面的示例中,getName() 将 "survive" 解构 :

class Person {
  constructor() {
    this.getName = this.getName.bind(this);
  }

  getName() {
    console.log(this);
  }
}

const {
  getName
} = new Person();

getName(); // Person { getName: [Function: bound getName] }

只需使用箭头方法:

const person = {
  getName: () => console.log(this),
};

是的。假设我正确理解你的问题,我们可以用一行代码来完成。

这当然不是最易读的方法,但它是我在个人项目中经常使用的方法:

const person = {
    getName: function() {
      console.log(this);
    }
  };

// IIFE for destructuring and applying changes inline
const { a, b, c } = (({ getName }) => ({ a: getName.bind(person), b: getName.bind(person), c: getName.bind(person) }))(person);

现在我们调用解构的道具:

a(); // { getName: [Function: getName] }
b(); // { getName: [Function: getName] }
c(); // { getName: [Function: getName] }

这里发生了什么?如果该行令人困惑,请继续阅读...

我们将所有内容包装在一个 IIFE 中,该 IIFE 接受 person 对象作为输入;我们将 getName 道具内联。1

最后,我们使用 getName 属性将每个调用显式映射到 bind - 从我们唯一的参数 person 中提取 - 对应于 a, b, c,我们正在从已解决的 IIFE 中解构它。

1好吧,可以说我在这里作弊了,因为我们有两个解构“语句”但是最终在同一个表达式中解析