字面量对象作为原型

5

这个问题更多关于支持和向后兼容性。我已经测试了以下代码。

function newFunc() {}

newFunc.prototype = {

    literal : {
        init : function() {
            console.log(this);
            this.test();
        },
        test : function() {
            console.log('test');
        }
    }
}

var inst = new newFunc();

inst.literal.init();

这个方法可行,但我在其他代码中没有看到过对象字面量作为原型的用法。这是有原因的吗?对我来说,这似乎是一种逻辑合理的编码方式,但如果存在严重的缺陷,我不想继续使用。


任何人都可以将 literal.init 替换为他们想要的任何内容,这个更改将反映在以前创建的每个实例上。如果没有中间的 literal 阶段,这是不可能的。 - Jon
1
我认为在JavaScript中几乎所有的东西都是对象,因此prototype也可以像其他对象一样被创建或重新分配。我已经看到过这种模式很多次,但我也很好奇它是否有一些缺点。我会说“没有”…但是好问题。 - basilikum
@squint 肯定可以。在这里唯一的“奇特之处”是只有一个真正位于原型上的属性,称为literal。其他方法只是该对象的属性,但这并不会破坏this的工作方式。 - Alnitak
2
@squint 嗯,好的,让我检查一下... 呃,是的,你说得对。那太糟糕了。 - Alnitak
1
@squint 感谢您的评论,这可能就是为什么我不会选择这条路的原因。没有双关语... 谢谢 - David Barker
显示剩余4条评论
4个回答

2

使用对象字面量创建函数原型是完全正常的,但通常只作为prototype对象的实际值。

不寻常的是在原型中包含一个嵌套对象,就像你所做的那样。

实际上,您只向原型添加了一个名为literal的对象。然后,所有方法都是该对象的属性。 这在技术上是有效的语法,但我以前从未见过它被使用过。 正如@ squint在评论中指出的那样,它似乎也破坏了this变量的工作方式,因为它将this绑定到在函数调用中使用的“下一个左侧”属性:

var inst = new newFunc();
inst.literal.init();
> Object { init: function, test: function }

this 已被设置为指向 .literal 对象,而不是已创建的实例。

实际上这只是一个例子,我打算使用多个嵌套对象作为原型或者混合使用嵌套对象和函数原型。感谢您的回答,这正是我需要的澄清。 - David Barker
关于编辑,是的,这正是我所期望的,而不需要使用上下文调用对象。再次感谢。 - David Barker
@DavidBarker 是的 - 不要在原型中嵌套属性。这会以意想不到的方式破坏事情。在我的示例中,我确实使用了上下文调用它,但该上下文是 inst.literal 而不是 inst。我是一位经验丰富的 JS 程序员,但这也让我感到困惑。 - Alnitak
是的,这是一个问题,可能会导致可读性和心智弯曲的上下文变化问题。我想我会坚持将嵌套文字分离出来,作为独立的文字或类原型。 - David Barker
@DavidBarker 将其拆分出来(并将其引用存储在原型中)不会有帮助 - 在原型中放置_nested_属性没有任何好的理由。 - Alnitak
我觉得你误解了我的意思,我不会这么做。我会彻底地将它从原型中删除;-) - David Barker

1
是的,对于原型使用字面量是正确的。例如,Mozilla在原型的文档documentation中明确使用了字面量。
var Customer = function(name) {
    this.name = name;
}

var Person = { // this is a literal
    canTalk : true,
    greet : function() { /* ... */ }
}

Customer.prototype = Person;

一些解释:prototype的值是一个对象,不管这个对象是如何创建的——使用简单的{}即可。通常会使用类似MyClass1.prototype = new MyClass2()这样的语句进行初始化,但是new只是创建一个新的对象。它还会设置prototype属性并执行构造函数(MyClass2),但是在新的对象上进行操作,不会对MyClass1产生任何影响(请参见此处的解释here)。
使用嵌套字面量没有任何区别。在问题中,原型被设置为{literal:{...}}。当您调用inst.literal.init()时,实际发生的是:
  1. 运行时会查看 inst 并检查对象是否为属性 literal 分配了一个值。
  2. inst 没有这样的属性,因此运行时继续使用其 prototype 属性。
  3. inst.prototype 引用它被初始化的文字对象。该对象已为属性 literal 分配了一个值。
  4. inst.literal 因此计算为嵌套文字 inst.prototype.literal
  5. 文字对象确实具有属性 init 的值。
  6. 调用 init() 函数。

这是 JavaScript (ECMA Script) 的原则之一,因此不应该存在兼容性问题。


你有注意到 OP 代码中实际上有一个嵌套的 literal 吗? - Alnitak
我知道原型是什么,以及它的工作原理。我的问题是,正如Alnitak所提到的,关于将对象嵌套为原型的更多内容。 - David Barker
2
@Mifeet 这确实有所不同 - 根据问题中的评论,嵌套属性会破坏this - Alnitak
不幸的是,在处理嵌套对象时,整个上下文都会发生变化。除非您明确地使用给定的上下文进行调用,否则我认为这是不可行的。 - David Barker
@Alnitak 好的,关于 this 我们总是需要小心谨慎。很明显,你的答案对David来说是正确的。 - Mifeet

0
你正在做的是将原型设置为JavaScript对象,并赋予多个属性。这是完全可以接受的,因为在JavaScript中,函数的行为与对象非常相似。JavaScript所做的只是将对原型属性的引用传递给继承的对象,因此它们将不会有一个它们可以访问的函数,而是一个对象。
你可以在MDN文档中看到实际上就是这样做的:
var Person = {
    canTalk : true,
    greet : function() {
        if (this.canTalk) {
            console.log("Hi, I'm "+this.name)
        }
    }
}
Customer.prototype = Person;

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fprototype


对不起,请问这是如何误用“字面值”? - Evan Davis
@Mathletics 这实际上是一个 JavaScript 的 对象字面量 - Alex W
1
@AlexW:忘记“JSON”中的“JS”吧。这只是对部分用于形成JSON语法的字面语法的一种认可。JSON是一种数据传输格式。在JavaScript程序中引用对象字面语法作为JSON是没有意义的,因为你不能直接使用该语法的结果进行数据传输。 - user1106925
1
我按照它们的原样编写,对象字面量。@squint已经给出了完美的回答,但您可以阅读规范 - Evan Davis
感谢您的澄清,撇开语义不谈,这是一个有用的答案。非常感谢。 - David Barker
显示剩余2条评论

-1

如果我理解正确,他们说你可以在 JavaScript (ECMA SCRIPT) 中做到这一点

http://en.wikipedia.org/wiki/Literal_(computer_programming)

但是我知道的是,如果你想实例化你的对象,旧版本的浏览器会有问题... 你不能使用Object.create()函数来实例化对象。

所以你通常应该这样做...

var foo = function(){};
foo.prototype = {func:function(){}}
var bar = new foo();

就像你这样或那样做 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接