Javascript 奇怪的“束缚”行为
我试图创建一个类似于React的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]);
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"