为什么要避免在JavaScript中创建对象?

WeA*_*ght 48 javascript

我正在关注W3Schools的JavaScript教程.在阅读每个页面时,他们会向用户注意"避免创建对象"并改为使用原始数据类型.他们给出了这样的理由:"代码变得难以理解,或者如果使用对象,执行速度将会降低".我们应该避免在JavaScript中创建对象吗?

例如:

var value = new Number(1);  // Avoid this
var value = 1;              // do something like this instead.
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 102

在JavaScript中,"避免创建对象"这一陈述是荒谬的,它在任何地方都有对象,并且是现存最面向对象的语言之一.但是"避免创建基元的对象版本",这是你引用的代码所做的,是有效的.也就是说,避免new String,new Numbernew Boolean.

JavaScript包含字符串,数字和布尔值的原始版本和对象版本.几乎没有任何理由明确地创建它们中的任何一个的对象版本,这样做确实会导致混淆; 看内联评论:

var s1, s2, n1, n2;

// These are false because with ===, an object is never equal to a non-object
s1 = new String("hi");
s2 = "hi";
console.log(s1 === s2); // false
n1 = new Number(42);
n2 = 42;
console.log(n1 === n2); // also false

// These are false because even with ==, two *different* objects are never equal
// (even if they're equivalent)
s1 = new String("what the...");
s2 = new String("what the...");
console.log(s1 == s2);  // also false
n1 = new Number(42);
n2 = new Number(42);
console.log(n1 == n2);  // also false
Run Code Online (Sandbox Code Playgroud)

字符串,数字和布尔值的对象版本主要用于使用为对象类型提供方法的相同机制来提供基元上的方法.当你这样做

console.log("foo".toUpperCase()); // "FOO"
Run Code Online (Sandbox Code Playgroud)

原始字符串创建临时对象"foo",然后toUpperCase从该对象读取该属性.由于对象继承自String.prototype,它有,toUpperCase并且一切都很好.一旦操作完成,临时对象就会被抛弃(除非有东西保留对它的引用,但什么也没有,没有什么可以用toUpperCase,你必须添加一个方法来String.prototype返回该对象,以便它保持在周围).

  • @supercat:没有我知道*如果*`String.prototype.toUpperCase`仍然是引擎在启动时给它的原始值.事实上,如果他们不这样做,我会感到非常惊讶(但是,我有时会相当惊讶). (2认同)

小智 10

它改变了操作符对数字,字符串和布尔值的直观表达方式:

  • ===当构造任何数字时,严格的compare()会中断,所以42 === 42是真的,而42 === new Number(42)不是,
  • ==当两个数字都是对象时,抽象比较()会中断,所以42 == new Number(42)是真的,而new Number(42) == new Number(42)不是,
  • 所述typeof操作者给出当多个被构造,所以不同的结果typeof(42)就是number,但typeof(new Number(42))object,
  • 转换为布尔值时,0为false,但new Number(0)为true,因此以下两个将具有不同的行为:

var a = 0;
if (a)
  console.log("not zero");
else
  console.log("zero!");     // "zero!"

var b = new Number(0);
if (b)
  console.log("not zero");     // "not zero"
else
  console.log("zero!");
Run Code Online (Sandbox Code Playgroud)

因此,应避免new Number,new Stringnew Boolean.

除此之外,还有使用/不使用new构造函数的问题.它源于几个事实:

  • 在JS中,构造函数是一个常规函数,使用this.foo语法来添加新的属性和方法;
  • 在没有new关键字的情况下调用时,this会成为全局对象,从而导致副作用.

结果,一个小错误可能会产生灾难性后果:

color = "blue";

var Fruit = function(color) {
  this.color = color;
  return this;
};

var apple = new Fruit("green");

console.log(apple.color);       // "green"  --  okay

console.log(color);             // "blue"  --  okay

var banana = Fruit("yellow");

console.log(banana.color);      // "yellow"  --  okay

console.log(color);             // "yellow"  --  wait, what?

console.log(banana.apple);      // "{ color: 'green' }"  --  what??

console.log(banana.document);   // "{ location: [Getter/Setter] }"  --  what???
Run Code Online (Sandbox Code Playgroud)

(这就是为什么有些人会在构造函数中添加显式检查,或者使用闭包.但这是另一个故事.)