4

问题是不言自明的。我知道可以扩展原始数据类型,string但是可以覆盖它吗?

这是一个在采访中被问到的问题。

4

4 回答 4

2

不,你不能覆盖任何东西。EcmaScript定义了原始类型 UndefinedNullBooleanNumberString; 这些是内部的,无论您在做什么(例如覆盖全局String构造函数)都将使用它们。文字的类型转换和评估不依赖于任何公共函数,而仅使用这些内部类型和为它们指定的算法。

当然,如果有人使用String(myval)而不是""+myval分配给全局String变量进行字符串强制,则会对该代码产生影响。任何内部使用仍将指向“旧”功能。


如果您在谈论原始类型的原型对象(当用作objects时),它们也不是可覆盖的。您可以扩展这些对象,但是一旦您分配给 eg Number.prototype,您就失去了对实际的原始数字原型对象的引用。Number 构造函数的示例规范:

新建对象的 [prototype] 设置为原始Number 原型对象,即( 15.7.3.1 )的初始值Number.prototype

于 2013-02-28T13:09:57.817 回答
1

是的(编辑:几乎)。打开 Javascript 控制台(如果您使用的是 Chrome,请按 F12)并输入

String = function(){alert('bang!')};

您可以覆盖(编辑:几乎)Javascript 中的所有内容——甚至是window全局上下文!evil.js是一个使用此技巧尽可能重写许多本机对象的库。

不用说,这是极其危险的。我执行了String上面的重新映射代码,自从写下它以来,我已经导致了 520 多个 Javascript 错误(我已经看到“砰”的警报很多次了)。原生对象无处不在,您不应该修改它们,以防 3rd 方代码以您不知道的方式依赖它们。这是 Prototype.js 失去人气的原因之一——因为它对原生对象的扩展通常会与其他代码的预期背道而驰。

编辑:正如Bergi回答中所指出的那样,绝对所有内容都可以被覆盖的事实不正确的断言。内联编辑。

于 2013-02-28T13:09:50.653 回答
1
  1. 您可以扩展本机类型的原型。

    String.prototype.moo = function() { 
       console.log( 'Moo!' ) 
    };
    'Cow says'.moo();
    >> "Moo!"
    
  2. 但是,除非您覆盖对整个对象的引用,否则您不能直接覆盖内置类型的构造函数:

    String = function() { 
       console.log( 'Custom function.' ) 
    };
    
    new String( 'Hello!' );
    >> "Custom function."
    >> String {} // now you've broken your website ;)
    
  3. ...但仍然:

    'Wat?!'
    >> "Wat?!" // you can still create strings by typing letters in quotes
    

所以......答案是“是但不是”。您可以使用本机类型(Number, Date, String...),但您不能完全从头开始重新定义它们。它们是您正在使用的 JS 引擎的一部分(很可能是本机 C++ 代码),这带来了一些限制。

于 2013-02-28T13:25:46.350 回答
0

像这样可能,但你必须总是成功而没有副作用。不是好的做法。

function Array() {
  var obj = this;
  var ind = 0;
  var getNext = function(x) {
    obj[ind++] setter = getNext;
    if (x) alert("Data stolen from array: " + x.toString());
  };
  this[ind++] setter = getNext;
}
var a = ["private stuff"];
// alert("Data stolen from array: private stuff");
于 2013-02-28T13:12:41.090 回答