《JavaScript Good Parts》附录书摘

第十章:Beautiful Features

提炼JavaScript的子集,这样我就不用解析整个语言,并且也就不需要描述整个语言了,我把这个语言叫做精简的JavaScript(Simplified JavaScript). 精简的JavaScript中都是好东西,包括一下主要的内容

  • 函数时顶级对象
    • 在精简的JavaScript中,函数是有语法作用域的闭包(lambda);
  • 基于原型继承的动态对象
    • 对象是无类型的,我们可以通过普通的赋值给如何对象添加一个新的成员属性.一个对象可以从另一个对象继承成员属性
  • 对象字面量和数组字面量
    • 这对创建新的对象和数组来说是一种非常方便的表示法,JavaScript字面量是数据交换格式JSON的灵感来源

附录A:Awful Parts

在本附录中,我会展示JavaScript的一些难以避免的问题特性,你必须知道这些问题并准备好对应的措施.

全局变量 Global Variables

  • 在JavaScript所有的糟糕特性之中,最为糟糕的一个就是它对全局变量的依赖.全局变量就是在所有作用域中都可见的变量.全局变量就是在所有作用域中都可见的变量.全局变量在小型程序中可能会带来方便.因为一个全局变量可以在程序的任何部分在任何时间修改,它们使得程序的行为变的极度复杂.在程序中使用全局变量降低了程序的可靠性.
  • 全局变量使得在同一个程序中运行独立的子程序变得更难.如果某些全局变量的名称碰巧和子程序中的变量名相同.那么它们会互相冲突,可能导致程序无法运行,而且通常难以调试.

作用域 Scope

  • JavaScript的语法来源于C.在所有其他类似C语言风格的语言里,一个代码块会创造一个作用域.代码块中声明的变量在其外部是不可见的.JavaScript采用了这样的块语法,却没有提供块级作用域:代码块声明的变量在包含次代码块的任何位置都是可见的.

  • 在大多数语言中,一般来说,声明变量的最好地方是第一次用到它的地方.但这种做法在JavaScript中反而是一个坏习惯,因为它没有块级作用域.更好的方式是在每个函数的开头部分声明所有变量.

  • 自动插入分号 Semicolon Insertion

    • JavaScript有一个自动修复机制.它试图通过自动插入分号来修正有缺陷的程序.但是,千万不要指望它,它可能会掩盖更为严重的错误.

    • 有时它会不合时宜的插入分号.请考虑在return语句中自动插入分号而导致的后果.如果在一个return语句返回一个值.这个值表达式的开始部分必须和return在同一行.

      1
      2
      3
      4
      return 
      {
      status:true
      };
    • 这看起来是要返回一个包含status成员元素的对象.遗憾的是,自动插入分号让它成为了返回undefined.自动插入分号导致程序被误解,却没有任何警告提醒.如果把( 放在上一行的尾部而不是下一行的头部可以避免该问题.

保留字 Reserved Words

  • 下面的单词在JavaScript中被保留
  • abstract boolean break byte case catch char class const continue debugger default
  • delete do double else enm export extends false final finally float for function goto
  • if implements import in instanceof int interface long native new null package private
  • protected public return short static super switch synchronized this throw throws
  • transient true try typeof var volatile void while with
  • 这些单词的大多数并没有在语言中使用
  • 它们不能被用来命名变量或函数,当保留字被用做对象字面量的键值时,它们必须被引号括起来.它们不能被用在点表示法中,所以有时必须使用括号表示法:
    • var method; //ok
    • var class; //非法
    • object ={boc:value}; //ok
    • object = {case: value}; //非法
    • object = {‘case’ :value}; // ok
    • object.box = value; //ok
    • object.case = value; //非法
    • object[‘case’] = value; //ok

typeof

  • typeof运算符返回一个用于识别其运算数类型的字符串所以: typeof 98.7 ,返回’number’,遗憾的是 typeof null返回’object’而不是’null’,这太糟糕了.其实有更简单也更好的检查null的方式: my_value === null

parseInt

  • parseInt是一个把字符串转为整数的函数.它在遇到非数字会停止解析.所有parseInt(“16”)与parseInt(“16 tons”)产生相同的结果.但是该函数会提醒我们出现了额外额文本就好了,但它不会那么做.
  • 那么该字符串第一个字符是0,那么该字符串会基于八进制而不是十进制来求值,在八进制中,8和9不是数字,所以parseInt(“08”)和parseInt(“09”)都产生0转为结果,这个错误会导致程序解析日期和时间时出现问题.幸运的是,parseInt可以接受一个基数转为参考,如此一来parseInt(“08”,10)结果为8,我建议你总是加上一个基数参数

+

  • +运算符可以用于加法运算或字符串连接.它究竟会如何执行取决于其参数的类型.如果其中一个字符串是空字符串,它会把另一个运算符转换成字符串并返回.如果两个运算符都是数字,它返回两者之合.否则,它把两个运算符都转为字符串并连接起来.这个复杂的行为是bug的常见来源.如果你要使用+去做加法运算.请保证两个运算数都是整数.

浮点数 Floating Point

  • 二进制的浮点数不能正确的处理十进制的小数,因此0.1+0.2不等于0.3.这是JavaScript中最经常被报告的bug,并且它是遵循二进制浮点数算术标准(IEEE 754)而有意导致的结果.但是它违背了大多数你在中学中学到的关于数学的知识.幸运的是,浮点数中的整数运算是精准的,所以小数表现出来的错误可以通过指定精度来避免

NaN

  • NaN是IEEE中定义的一个特殊的数量值.它表示的不是一个数字,尽管下面的表达式返回的是true: typeof NaN === ‘number’//true
  • 如果NaN是属性运算中的一个运算数,那么结果就是NaN.所以,如果你有一个公式链产生了NaN的结果,那肯定是其中某一个输入项是NaN,要么在某个地方产生了NaN
  • 你可以对NaN进行检测,typeof不能识别数字和NaN,而且NaN不等于它字节.所以下面的代码结果让人惊讶:
  • NaN === NaN //false
  • NaN != NaN //true
  • ps:此处黑人问号
  • javaScript中提供了一个isNaN函数,可以分辨数字和NaN

伪数组 Phony Arrays

  • JavaScript没有真正的数组,这也不全是坏事.JavaScript的数字确实非常容易使用,你不必给它们设置维度,而且它们永远不会产色越界错误,但是它们的性能相比真正的数组可能相当糟糕.
  • typeof运算符不能辨别数组和对象.要判断一个值是否为数组,你还需要检查它的constructor属性
  • if (my_value && typeof my_value === ‘object” && my_value.constructor === Array)

假值 Falsy Values

  • JavaScript拥有一组数量齐大的假值
类型
0 number
NaN(非数字) number
“”(空字符串) String
false Boolean
null Object
undefined Undefined
  • 这些值全部都等同于假,但是它们是不可互换的

Object

  • JavaScript的对象永远不会是真的空对象.因为它们可以从原型链中取得成员属性
作者

liukun

发布于

2020-06-22

更新于

2020-06-22

许可协议