JavaScript中的对等继承
在观看Douglas Crockford关于高级JavaScript的讲座时,他提出了寄生继承的概念,本质上就是让构造函数调用其他构造函数来修改所讨论的对象。这是他的密码:JavaScript中的对等继承,javascript,Javascript,在观看Douglas Crockford关于高级JavaScript的讲座时,他提出了寄生继承的概念,本质上就是让构造函数调用其他构造函数来修改所讨论的对象。这是他的密码: function gizmo(id, secret) { secret = secret || {}; secret.id = id; return { toString: function () { return "gizmo " + secret.id; } }; } fun
function gizmo(id, secret) {
secret = secret || {};
secret.id = id;
return {
toString: function () {
return "gizmo " + secret.id;
}
};
}
function hoozit(id) {
var secret = {},
that = gizmo(id, secret);
that.test = function (testid) {
return testid === secret.id;
};
return that;
}
var myHoozit = hoozit(20);
console.log(myHoozit.test(20)); //returns true
我理解代码,这里没有太难掌握的东西。混淆发生在hoozit
功能中。如果不设置secret={}
,则不会返回atrue
这是令人困惑的,因为在gizmo
函数中,您会看到secret=secret | |{}
应该为我们解决这个问题。。。但事实并非如此
为什么当在hoozit
函数中没有传递第二个参数(Chrome和Firefox都中断)时,gizmo
函数中的短路不能正常工作
为什么当在hoozit
函数中没有传递第二个参数(Chrome和Firefox都中断)时,gizmo
函数中的短路不能正常工作
很简单,因为您无法访问secret
中的that.test
,因为它不在该范围内:
function hoozit(id) {
var that = gizmo(id);
that.test = function (testid) {
// secret is not defined in this or in any higher scope
// hence you get a refernece error
return testid === secret.id;
};
return that;
}
存在的唯一secret
对象是gizmo
函数的本地对象
如果您定义它,只是不将它传递给
gizmo
,那么secret=secret | |{}
将计算为secret={}
,即在gizmo
函数中创建一个新对象。该值只能在gizmo
函数中访问,与hoozit
函数中的secret
变量完全无关。gizmo
中的secret
对象与hoozit
中的对象不同
function hoozit(id) {
var secret = {}, // secret object is created here
that = gizmo(id);
that.test = function (testid) {
// you never set `secret.id`, hence the comparison results in `false`
return testid === secret.id;
};
return that;
}
secret=secret | |{}
没有什么问题,它按预期工作。让我们看一个简单的例子
function Foo(baz){
baz = baz || {};
baz.boo = 1;
}
function Bar(baz){
baz = baz || {};
Foo(baz);
return baz;
}
如果我们调用Bar()
,我们将向Foo传递一个对象。然后,它通过设置boo
属性来解析对象。好极了
现在,假设我们的条形函数如下所示:
function Bar(baz){
baz = baz || {};
Foo();
return baz;
}
唯一的区别是我们没有将对象传递给Foo。因此,Foo正在其作用域内创建一个对象。我们在新对象上设置一个属性,然后函数结束。该对象不是Bar的父范围,因此Bar永远不知道该对象已创建,也无法访问它。在接下来的几毫秒内,对象将从RAM中删除,因为没有对它的引用
你的问题并非如此。
toString
函数引用它。由于外部作用域已完成,因此它现在是toString
函数的局部变量。如果我们没有传递secret
对象,那么它永远不会离开该范围。它必须以某种方式出口
更合乎逻辑的策略是将其创建为原始对象的属性。我们的秘密很容易被知道JavaScript是什么的用户访问,所以我们应该省去一些麻烦,并使用合理的继承方法
如果您不知道SomeFunction.call
可以接受任意数量的参数。第一个参数是您希望在函数中成为的this
,其余参数只是常规参数
function gizmo() {
this.toString = function () {
return "gizmo " + this.id;
};
};
function hoozit(id) {
this.id = id;
gizmo.call(this); // allow gizmo to manipulate this object
this.test = function (is) {
return this.id === is;
};
};
h = new hoozit(1);
console.log(h.test(1)); // true
console.log(h.toString()); // "gizmo 1"
您需要
secret={}
它在
return testid===secret.id处出错代码>因为机密
需要存在
您可能正在寻找的主要魔法是,正在填充secret.id
,因为所有操作都发生在gizmo()
中。答案是这行:that=gizmo(id,secret)代码>
secret
被传递给gizmo,在JavaScript中,对象通过引用传递。这意味着,如果您有一个本地对象,并将该对象作为参数传递给另一个函数,则对该对象的任何操作都将在本地反映
如果不希望发生这种情况,则需要对参数进行某种复制/克隆(库错误地使用了克隆这个术语来表示深度复制)。但在本例中,您确实希望更改gizmo中的secret
,以更新hoozit中的secret
,因此一切都正常工作
下面是另一种书写方式:
function gizmo(secret) { // only receive secret, which already has an "id"
secret = secret || {'id':null}; // if secret not passed create it with a default "id"
return {
toString: function () {
return "gizmo " + secret.id; // the reason why we needed a default "id"
}
};
}
function hoozit(id) {
var secret = {'id':id}, // create a object and set key "id" to hoozit's argument
that = gizmo(secret); // only pass secret
that.test = function (testid) {
return testid === secret.id;
};
return that;
}
var myHoozit = hoozit(20);
console.log( myHoozit.test(20) ); //returns true
如果你不声明秘密
,你怎么能在hoozit.test
中测试testid==secret.id
?@Zirak好吧,如果我们把它改成那样的.id
我想如果短路像我们想象的那样工作,它会工作。如果你在hoozit没有这个,当调用gizmo时,它会抛出一个引用错误。你能发布你修改过的代码吗?你认为什么应该起作用?秘密不能交朋友!但是,为什么要使用私有变量呢?有人可以轻松地获取该代码,将其修改为成员变量,然后重新创建该类。通常的规则是把你想公开的东西都记录下来,其他的东西都是没有记录的,不应该使用。这对我不起作用。如果我在hoozit
中取出secret
,它就会破裂。@Sethen:这就是我要说的,我解释了原因,不是吗?让我困惑的是secret=secret |{}
。。。这似乎不起作用?我正在调用gizmo,第二个参数中没有任何内容。我想我只是不理解这一点。我会假设这将与that.id
一起工作,而不是secret.id
,但它不工作。它正在工作。如果secret
是未定义的
,secret=secret | |{}
基本上是secret={}
,即它在gizmo
内创建一个新对象。该对象不能从外部访问,它是函数的本地对象。我喜欢使用call