Crockford 原型继承的小缺点
只是在 JS 中尝试不同的继承技术,并遇到了一些关于 Crockford 的原型继承模式的稍微令人不安的事情:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var C,
P = {
foo:'bar',
baz: function(){ alert("bang"); }
}
C = object(P);
一切都很好 - 除了当你登录到控制台时 - 对象显示为 F。我见过经典的您可以在其中重新指向构造函数的模拟 - 是否有类似的方法来强制对象(控制台)引用?
Just experimenting with different inheritance techniques in JS, and came across something mildly discomfiting about Crockford's Prototypal Inheritance pattern:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var C,
P = {
foo:'bar',
baz: function(){ alert("bang"); }
}
C = object(P);
It's all good - except when you log to console - the object appears as F. I've seen classical emulation in which you can repoint the constructor - is there a similar method to coerce the objects (console) reference?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题在于它引用了构造函数的名称。这很快就变成了关于函数表达式和语句以及 name 属性的讨论。事实证明,如果不使用 eval,在运行时创建新的命名函数是完全不可能的。名称只能使用函数语句
function fnName(){}
指定,并且除了评估之外不可能动态构造该代码块。var fnExpression = function(){}
生成分配给变量的匿名函数。函数的name
属性是不可变的,所以它已经完成了。使用Function("arg1", "arg2", "return 'fn body';")
也只能生成匿名函数,尽管与 eval 类似。这基本上只是 JS 规范中的一个疏忽(Brendan Eich 表示他很遗憾以大约 10 年前的方式定义显示名称),并且正在讨论 ES6 的解决方案。这将引入更多语义来导出调试工具的函数显示名称,或者可能是设置和调整它的显式方法。
现在您有一个途径:eval,或可配置代码的某种其他形式的后期执行。 (用任何其他名称进行 eval...)
单独的函数语句不会从 eval 返回,但会执行 1 &&
fnStatement
将事物强制转换为可返回的表达式。(Harmony 代理还允许设置报告名称的函数,您可以在不使用 eval 的情况下配置这些名称,但目前除 Node.js 和 Firefox 之外无法使用)。
我要在这里指出的是,所有那些被克罗克福德和其他许多人攻击过的“邪恶”功能都有它们的位置。
eval
、with
、扩展原生都支持特定的技术,否则这些技术是完全不可能的,并且在适当的场合使用它们并没有错。大多数人很可能没有资格判断何时是合适的时机。在我看来,在等待解决方案时使用eval
无害地弥补糟糕的语言语义和工具是完全可以接受的,只要您不将任意代码注入其中,就不会对您造成任何伤害评估声明。The issue is that it's referring to the
name
of the constructor function. This quickly becomes a discussion about function expressions and statements and the name property. Turns out is is completely impossible to create a new named function at runtime without using eval. Names can only be specified using a function statementfunction fnName(){}
and it's not possible to construct that chunk of code dynamically aside from evaling it.var fnExpression = function(){}
results in an anonymous function assigned to a variable. Thename
property of functions is immutable so it's a done deal. UsingFunction("arg1", "arg2", "return 'fn body';")
also only can produce an anonymous function despite being similar to eval.It's basically just an oversight in the JS spec (Brendan Eich stated he regrets defining the display name the way he did 10 or so years ago) and a solution is being discussed for ES6. This would introduce more semantics for deriving a function's display name for debug tools or perhaps an explicit way to set and adjust it.
For now you have one route: eval, or some other form of late execution of configurable code. (eval by any other name...)
The function statement alone won't return from eval, but doing 1 &&
fnStatement
coerces the thing into an expression which is returnable.(Harmony Proxies also allow setting up functions that report names which you can configure without eval but that's not usable except in Node.js and Firefox currently).
I'll make a note here that all those "evil" functions that have been shat upon by Crockford and many others ALL have their place.
eval
,with
, extending natives all enable specific techniques which are otherwise completely impossible and it's not wrong to use them when the occasion is right. It's just likely that most people aren't qualified to make the judgement of when that time is right. In my opinion usingeval
harmlessly to make up for poor language semantics and tools while waiting for a solution is perfectly acceptable and won't cause you any harm as long as you're not funneling arbitrary code into that eval statement.如果我记录对象,我可以看到:
Object { foo="bar", baz=function()}
,所以我不明白你的问题......无论如何,可以使用 Object.create( ) 而不是 Crockford 的函数:
console.log (C):
Object { foo="bar", baz=function()}
If I log the object I can see:
Object { foo="bar", baz=function()}
, so I don't understand your problem...Anyway, can use Object.create() instead of Crockford's function:
console.log (C):
Object { foo="bar", baz=function()}