• JavaScript:undefined不是字面量


    今天看了一下《高性能JavaScript》,发现一个问题,就是书中把undefined也当成了字面量(直接量),这是不对的.

    中文版:

    英文原版:

    Literal values

    Any value that represents just itself and isn’t stored in a particular location. JavaScript can represent strings, numbers, Booleans, objects, arrays, functions, regular expressions, and the special values null and undefined as literals.

    什么是字面量

    我想,这个名词很难去定义,因为ES规范上也没有明确给出到底什么是字面量.维基百科上是这么定义的:

    一个字面量就是在源代码中表示某个固定值的符号.

    我的理解是:编译器或者解释器看到一个字面量,就知道它表示的是哪个具体的值.比如我们把符号1规定为值1的字面量,这只是规定,如果把符号一规定成是值1的字面量,那么一就成了字面量.再比如字符串字面量,常见的表示法是用引号"string",但在perl中,q/string/也是一个字符串字面量.也就是说,,每种语言的字面量有不同的符号表示法.字面量和标识符是冲突的,这也就是为什么标识符不能以数字开头,a1可以是标识符,11可就不行了.null是字面量(同时也符合标识符的语法),所以得把它规定成为保留字,不能作为标识符使用.

    undefined不是字面量

    书中说特殊值undefined也是字面量,这是不对的.我们可以在ES5规范中找一下,只能找到下面这些字面量语法:

    ArrayLiteral
    BooleanLiteral
    DecimalIntegerLiteral
    DecimalLiteral
    HexIntegerLiteral
    JSONBooleanLiteral
    JSONNullLiteral
    NullLiteral
    NumericLiteral
    ObjectLiteral
    OctalIntegerLiteral
    RegularExpressionLiteral
    StrDecimalLiteral
    StringLiteral
    StringNumericLiteral
    StrNumericLiteral
    StrUnsignedDecimalLiteral

    你可以看到,这里面有数组字面量,布尔值字面量,十进制整数字面量等,就是没有undefined字面量.为什么呢,那我们写在JavaScript源代码中的undefined到底是什么.

    undefined是什么

    ES5规范中讲了:

    8.1 Undefined类型

    Undefined类型只有一个值,叫做undefined.任何没有被赋过值的变量的值为undefined.

    Undefined是种类型,就像Number类型一样.Number类型有无数个值,比如0,1,3.14等等.String类型也有无数个值,比如"123","abc"等等,Boolean类型有两个值true和false.而Undefined类型只有一个值,就是undefined.类似的还有Null类型,它也只有一个值null.

    ReservedWord ::                 //保留字包括下面的几种:
    Keyword                         //关键字
    FutureReservedWord              //未来保留字
    NullLiteral                     //null字面量
    BooleanLiteral                  //布尔值字面量,也就是true和false

    null是个保留字,你不能把null作为变量名,单独的null(不被包含在字符串或正则字面量中)在JavaScript代码中的意思就是null值.而undefined不是保留字,你可以定义一个名为undefined的局部变量.而且JavaScript引擎已经内置了一个undefined全局变量,它的值是undefined.

    15.1.1 全局对象的属性

    15.1.1.1 NaN

    NaN的值是NaN (see 8.5).

    15.1.1.2 Infinity

    Infinity的值是+∞ (see 8.5). 

    15.1.1.3 undefined

    undefined的值是undefined (see 8.1).

    更明确点讲,我们写在JavaScript代码中的undefined,并不是undefined值本身.而是一个局部变量或者是全局对象的一个属性.但大部分时候它们的值是undefined.NaN和Infinity也同理.

     有什么影响

     维基百科上有一段话讲了undefined的这个特点:

    注意:根本不存在undefined字面量.因此(x == undefined)并不能说明变量x的值就是undefined,因为在ECMAScript 5之前的规范中,可以使用语句var undefined = "I'm defined now"来修改undefined的值.更可靠的检测方法是(typeof x === 'undefined').

    现在有不少人在自己的代码中使用了jQuery的这种写法,为什么要这么写呢.

    ;(function(window,undefined){

    })(window)

    其中一个原因就是防止全局的undefined变量被修改成其他值,但随着ES5的普及以及几乎不可能有人去改这个值,我觉得这种考虑越来越多余.这种写法还有其他两个考虑,一个是避免查找作用域链(这种性能差异真的值得考虑吗?),还有就是为了代码压缩了.

    证明

    我们可以使用Ariya Hidayat(phantomjs的作者)写的基于Esprima(纯JavaScript编写)ECMAScript解析器来解析一下这几个符号

    Infinity 
    undefined
    NaN
    null 100

    解析得到的语法树是:

    {
    "type":"Program",
    "body":[{
    "type":"ExpressionStatement",
    "expression":{
    "type":"Identifier",
    "name":"Infinity" } }, { "type":"ExpressionStatement",
    "expression":{
    "type":"Identifier",
    "name":"undefined" } }, { "type":"ExpressionStatement",
    "expression":{
    "type":"Identifier",
    "name":"NaN" } }, { "type":"ExpressionStatement",
    "expression":{
    "type":"Literal",
    "value":null,
    "raw":"null" } }, { "type":"ExpressionStatement",
    "expression":{
    "type":"Literal",
    "value":100,
    "raw":"100" } } ] }

    可以看到,前三个名称都是标识符,后两个才是字面量.如果你还不放心,可以试试SpiderMonkey自己的解析器,运行结果如下:

    js> Reflect.parse('undefined').body[0].expression.type
    "Identifier" js> Reflect.parse('null').body[0].expression.type
    "Literal"
  • 相关阅读:
    【iOS】获取App的常用文件路径
    【iOS】如何在Objective-C中声明Block?
    实用终端小命令
    iOS开发之NSBundle加载自定义cell需指定其的identifier
    【转】nonatomic, retain,weak,strong用法详解
    iOS控制台打印NSLog增强版
    iOS 内存中的ViewController释放
    iOS ViewController生命周期
    Netty (一) IO 基础篇
    多线程(七) 线程池的实现原理分析
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/2765096.html
Copyright © 2020-2023  润新知