原语的Literal vs Constructor表示法,对于初学者来说更合适?

时间:2014-01-28 02:10:57

标签: javascript constructor

所以我是我大学班级的助教,对于如何为绝对初学者程序员提供数据类型(我以前从未编程过),我有点意见不一致。我的老师告诉学生他们必须严格使用构造函数来创建原始数据类型,如数字和字符串,她的理由是将JavaScript视为强类型,这样学生将习惯于未来的语言。我理解为什么,但我认为它有不好的权衡。

var num = new Number(10); // This is encouraged.

var num = 10; // This is discouraged (students will lose points for doing this).

我的导师没有对这些进行区分,并且学生被告知要将他们视为原始的数字,字符串等。虽然我相信至少对于不熟悉使用datatype.valueOf()的初学者必要的时候,根本不知道对象是什么。文字符号(并且我认为它)更合适和更标准,另一种方式会引起混淆。由于构造函数符号存在一致性问题,因为它们是对象(我不希望学生担心这一点)。例如,这些对初学者没有意义:

var num1 = new Number(1);
var num2 = new Number(1);

if(num1 === num2) ... ; // Does not run.    

if(num1 == num2) ... ; // Does not run.

if(num1 == 1) ... ; // But this does.    

var num2 = new Number(2);

if(num1 < num2) ... ; // So does this.

switch(num1){
    case 1:
        ...  // Does not run.
        break;
    default:
        ... // This runs
        break;
}

正如你所看到的那样,对于那些只是学习if statement的人来说,这会让人感到困惑。我觉得她好像鼓励不良行为并劝阻良好行为。那么你认为原始值的文字和构造函数符号之间有什么看法,它被认为更标准/更合适,哪个更适合初学者使用?

4 个答案:

答案 0 :(得分:6)

new Number(1)1不一样。第一个是Object,后一个是Number

var num = new Number(1);
typeof num;    //object

var num = 1;
typeof num;    //number

为了获得构造函数创建的对象的值,必须每次使用valueOf 才能获得正确的结果。

if( new Boolean(false) ){            if( new Boolean(false).valueOf() ){
    console.log("True");                 console.log("True");
}else{                               }else{
    console.log("False");                console.log("False");
}                                    }

//> True                             //> False
//Student Be Like:                   //Student Be Like:
// What?! That doesn't even make     //Okay that makes sense.
// sense!

由于使用构造函数只会使更多学习者感到困惑并且会在程序的进一步开发中引起更多问题,因此永远不应使用IMO原语构造函数。 (在某些情况下除外。)

此外,每次声明变量时使用构造函数都会极大地影响执行速度,因为为新对象分配空间所需的时间比简单的64位浮点数要长。以下是比较:http://jsperf.com/constructors-vs-literalss

TL;博士

var num = new Number(10);  // bad, never do this, prone to errors

var num = 10;              // do this instead

每当有文字并且你不使用它时:非常可能是错误的代码。

new Boolean(false);    // bad
new String("foo");     // bad
new Object();          // not as bad as the ones above, but still bad
new Array(10);         // bad, it initializes the array with
                       //  not-your-normal `undefined`

答案 1 :(得分:6)

作为花费额外时间在每个Python程序中创建main函数的人,以便我们在时间到来时为Java public static void main做更多的准备,有一个地方可以稍微减少 - 在学习如何编程方面比最好的做法。

现在老师自己,在JavaScript中使用构造函数不是那个地方。首先,它导致控制流程的不当行为,这是编程开始步骤的重要部分。其次,它通过在Web开发人员的工具包中错误地教授基本语言而使学生感到不适。最后,它没有为构造函数准备一个!作为旁注,JavaScript并不容易落入任何典型的编程范例,因此不适合作为四年制大学课程中的第一语言(在这位作者看来)。

构造函数阻止对控制流的理解

首先,让我们看看控制流程。如果没有控制流,初学者可能永远无法构造比Hello world更复杂的东西。对于初学者来说,对于控制流篮中的每个项目有充分的了解,这是绝对必要。一位优秀的讲师将为每种类型提供几个示例,并详细说明truetruthy之间的差异。

构造函数完全破坏了初学者对控制流的理解,如下例所示:

var myBool = new Boolean(false);
if (myBool) { console.log('yes'); } // 'yes' is logged to the console.

是的,这是JavaScript的'wat'时刻之一。这种语言应该这样吗?可能不是。可以?绝对。初学者需要看到有意义的简单例子给初学者。首次出发时,边缘情况没有脑空间。像这样的例子只对教授应该教的人不利。

构造函数在JavaScript中没有位置

这个更基于意见。需要注意的是:JavaScripters可能会在构造函数中使用它们来转换类型(即Number('10')),但通常有更好的方法。

实际上,每次在JavaScript中使用构造函数时,都会被误用。我想的是,如果想要一个字面数字,那就写出来。不需要所有额外的输入,更不用说使用构造函数的各种类型冲突和隐藏的陷阱](https://stackoverflow.com/a/369450/1216976)。

值得注意的是,JSLint和JSHint(由比我更聪明的人编写)都不鼓励以这种方式使用构造函数。

答案 2 :(得分:1)

是否是初学者,更喜欢原始人。 我认为这个问题与Java中的原始或盒装原始问题没有什么不同。

使用原语更简单,更具表现力: Number,Boolean或String虽然JavaScript中的可用对象是对象,而不仅仅是值。从有效的Java中引用Joshua Bloch:“对象具有与其价值观不同的身份。”当您引用Number对象时,它与数字值不同。当我们处理数字时,我们通常会感到困扰。基元可以节省额外的工作量,将其理解为开发人员和读者的对象。

等于比较:等于具有=运算符的对象的比较实际上是参考比较,这总是被误解并创建错误的范围。

原语更快:(需要证明吗?)为什么在对象创建时只为了对我们重要的价值而烦恼?

在公开函数中进行类型验证: JavaScript类型松散,我们有时需要对公开函数进行故障安全类型检查。对类型进行一般性检查:typeof param ===“string”或“number”。你给我一个“对象”,我不会花时间猜测你可能会传递什么对象..

我使用Number构造函数的唯一地方是将字符串解析为数字。我的工作主要是开发银行产品,我宁愿拿NaN而不是使用parseInt猜测一个数字(完全不同的问题)。

答案 3 :(得分:1)

首先,如果您是大学的助教,那么您应该告诉您的教授不要将JavaScript作为入门语言教给学生。原因是JavaScript是:

  1. 对于它想要的语言类型感到矛盾:functional vs object-oriented
  2. unintuitive:很多次,它的行为方式与预期不符。
  3. 太冗长:有太多的语法元素会转移你的注意力。
  4. JavaScript不是一种合适的介绍性语言。它甚至不是一种合适的制作语言,这就是为什么我们有LiveScript和其他编译到JavaScript的语言。

    由于你是一名助教,我强烈建议你阅读Bret Victor关于Learnable Programming的精彩博文。它描述了一个很好的入门编程语言的组成部分。

    无论如何,我离题了。回到最初的问题,“Literal vs Constructor notation for primitives,这对初学者更合适?”这个问题很简单。你知道答案:文字。

    我猜测你的教授正试图向学生讲授以下几点:

    JavaScript中的所有内容都是对象。

    现在,尽管将JavaScript中的所有内容都视为对象是理想的,但这种理想实在太过分了。基元不是对象。基元包括:

    1. 未定义。
    2. 空。
    3. 布尔。
    4. 号。
    5. 字符串。
    6. 我认为你的教授正在混淆JavaScript与Java,它主张所有东西都是一个对象(实际上这不是真的,因为你除了类,接口等之外还有原语)。

      JavaScript比Java更面向对象,因为一切(除了基元)都是一个对象。您没有JavaScript中的类。对象只是从其他对象继承。

      简而言之,这是一个很好的类比,可以解释原始与参考值对学生的区别:Primitive value vs Reference value

      现在虽然你在JavaScript中有原语,但你也有这些原语的包装对象(即BooleanNumberString构造函数),以便将它们视为对象。

      这些包装器公开了几种有用的实用方法。例如,您可以执行:42..toString(2)以二进制形式获取42的值作为字符串。正如您所看到的,当您在基元上调用方法时,JavaScript会自动将原始值42强制转换为Number对象。因此,明确地为基元创建包装器对象是没有意义的。阅读The Secret Life of JavaScript Primitives

      事实上,如果你真的想要一个包装器对象而不是一个原语(出于性能原因),我会按如下方式进行:

      Object.prototype.getObject = function () {
          return this;
      };
      
      var yes = true.getObject();
      var answer = 42..getObject();
      var greet = "hello".getObject();
      

      这实际上对我来说更有意义。你正在使用一个原语,强制进入一个对象并返回强制参考值。顺便说一下,42是对The Hitchhiker's Guide to the Galaxy的暗示。

      除了更简洁之外,使用文字而不是包装对象的另一个好理由是数学等价。正如您在问题中所描述的那样,希望能够比较两个数学等价值。对象破坏了数学等价。由于对象具有不同的标识,因此两个数学上等效的对象可能在逻辑上不等同。例如:

      console.log(new Number(42) === new Number(42)); // false
      

      要解决此问题,您需要使用valueOf将数字转换为基元:

      console.log(new Number(42).valueOf() === new Number(42).valueOf()); // true
      

      编写像这样的代码真是愚蠢。当你能编写干净可理解的代码时,为什么要限制自己不必要的黑客?

      console.log(42 === 42); // true
      

      每个人都知道42确实是42但是很少有初学者会理解为什么两个在数学上等价的对象在逻辑上是不同的。

      总而言之,当你教某人如何编程时,你需要确保你的代码是直观的(即它不应该以意想不到的方式工作)。如果它不按预期的方式工作,那么你做错了。你最终会挣扎于语言,而不是编写有用的程序。