Javascript 奇怪的“束缚”行为

Javascript 奇怪的“束缚”行为,javascript,Javascript,我试图创建一个类似于React的createClass函数的函数。它应该接受一个POJO,并将其转换为构造函数,该构造函数可以使用其他参数调用 代码如下: function createClass(obj) { return function(args = {}) { Object.keys(obj).forEach(k => this[k] = obj[k]); Object.keys(args).forEach(k => this[k] = args[k]);

我试图创建一个类似于React的
createClass
函数的函数。它应该接受一个POJO,并将其转换为构造函数,该构造函数可以使用其他参数调用

代码如下:

function createClass(obj) {
  return function(args = {}) {
    Object.keys(obj).forEach(k => this[k] = obj[k]);
    Object.keys(args).forEach(k => this[k] = args[k]);
    Object.keys(this.actions).forEach(k => this.actions[k] = this.actions[k].bind(this));
    console.log('binded to', this);
  }
}

const MyClass = createClass({
  actions: {
    foo: function() {
      console.log('actions.foo');
      this.request();
    }
  },
  foo: function() {
    console.log('foo');
    this.request();
  }
});

const req1 = function() {
  console.log('req1 called')
}

const req2 = function() {
  console.log('req2 called')
}

const c1 = new MyClass({request: req1});
const c2 = new MyClass({request: req2});

// As expected
c1.request();
c2.request();
console.log('---')

// As expected
c1.foo();
c2.foo();
console.log('---')

// Error: both call req1
c1.actions.foo();
c2.actions.foo();
console.log('---')
我不明白为什么调用
c2.foo()
会按预期工作,但调用
c2.actions.foo()
会从另一个实例调用方法。怎么可能呢

另外,

因为在这一行:

Object.keys(obj).forEach(k => this[k] = obj[k]);
…您正在将
操作
(引用,而不是数组)复制到新对象。稍后您将更新该数组的内容,但它们都共享同一个数组。由于您正在对
操作
中的函数调用
绑定
,因此第一次绑定到该第一个实例的时间;随后,它们不会这样做,因为
bind
的整个要点是它忽略了调用它的
this
,因此对绑定函数调用
bind
没有任何作用(关于
this
)。例如:

因此,通过
actions
对函数的任何调用都将始终使用
this
调用这些函数,引用您创建的第一个实例

解决方案:复制数组内容(至少是浅拷贝),例如使用
对象。分配

下面是删除了一些测试的代码,但检查了
c1.actions==c2.actions
,表明它是
true
(它们使用相同的数组):

函数createClass(obj){
返回函数(args={}){
Object.keys(obj.forEach)(k=>this[k]=obj[k]);
Object.keys(args.forEach(k=>this[k]=args[k]);
Object.keys(this.actions).forEach(k=>this.actions[k]=this.actions[k].bind(this));
//log('binding to',this);
}
}
const MyClass=createClass({
行动:{
foo:function(){
//console.log('actions.foo');
这个.request();
}
},
foo:function(){
//console.log('foo');
这个.request();
}
});
常数req1=函数(){
console.log('req1已调用')
}
const req2=函数(){
console.log('req2已调用')
}
const c1=新的MyClass({request:req1});
const c2=新的MyClass({request:req2});

console.log(c1.actions==c2.actions);//真的
哇,谢谢!我需要一些时间来理解这一点。但我仍然不明白为什么
操作
对象成为共享对象。我认为它将只在创建的实例和构造函数参数中的临时对象(例如{request:req1})之间共享。秒实例也是如此,但现在它们之间都是。也许我对构造函数还是不太了解…@saintcrawler:这与构造函数无关,因为当你做
this[k]=obj[k],则与实例共享传递给
createClass
的原始
actions
对象,然后对其进行修改。因此,所有实例都使用相同的对象。这就是上面的建议修复它的原因,因为我们使用
this[k]=Object.assign({},obj[k])
复制对象,使实例在我们修改它之前拥有自己的对象。但是,由类创建的所有实例(从
createClass
返回)都应该共享相同的
操作
对象。这就是我想要的。例如,所有实例都使用相同的
actions.foo
函数,但是
this.request()
内部
foo
应该调用它们自己的
request
函数。换句话说,
actions
对象中的所有函数都应该在类的原型中,但应该使用正确实例的
this
调用。我不熟悉javascript,可能还有另一个更好的解决方案。@saintcrawler:如果你在对象上循环,将对象上的函数绑定到最后创建的实例上,它们就不能共享同一个
操作
对象。@t.J.Crowder似乎很难理解,当
const c1=new MyClass时({request:req1});
这一行被执行时,c1.actions.foo将与c1绑定,c1.request()将打印“req1 called”。这很好。之后,当这一行
const c2=new MyClass({request:req2});
被执行时,c2.actions.foo将与c2绑定,因为这一行
…this.actions[k]=this.actions[k].bind(this)
并调用它应打印“req2 called”。我知道两者共享相同的操作,但为什么req2没有得到更新??您能帮助我理解吗?
var f = function() { console.log(this.name); };
var f1 = f.bind({name: "first"});
f1();                                                         // "first"
var f2 = f1.bind({name: "second"});
//       ^^------ Note we're using an already-bound function
f2();                                                         // Also "first"