美文网首页
读书笔记之JavaScript语言精粹

读书笔记之JavaScript语言精粹

作者: peakhell | 来源:发表于2017-11-24 16:04 被阅读14次

作为一个前端开发人员, js的一些坑已经踩了不少, 但这本书总结的非常好, 把精华部分和糟粕部分都非常系统详细的列出来, 个人认为附录部分的js毒瘤与糟粕非常值得一读, 如果你是刚开始接触js, 那就更值得你好好看看了, 绝对能少踩很多坑. 这里做个读书笔记, 总结一下这本书的附录部分, 也就是js的坑.

  • 全局变量

    对全局变量的依赖可能是JavaScript最糟糕的特性. 很多编程语言也有全局变量, 例如Java使用public static 关键字定义全局变量, 但在JavaScript中, 由于没有连接器(linker), 所有的编译单元都在如到一个公共全局对象中(也就是window对象). 也许在小型程序中这会带来很多便利, 但当程序变得复杂时, 全局变量便会使程序变得难以维护, 因为无论在全局哪一个地方更改全局变量的值, 全局变量都会改变. 更糟糕的是如果我们没有使用var关键字进行变量的定义, JavaScript会默认该变量为全局变量, 不管在程序的哪个地方.

    function test(){
      globle = 10;
    }
    test();
    console.log(globle)   //10
    

    由于globle没有用var关键字修饰, JavaScript会把globle当成全局变量, 导致在函数外也可以使用. 这是一个非常糟糕的设计, 因此声名变量时, 一定要在前面加关键字 var.

  • 作用域

    JavaScript与C语言类似, 都是用{}来表示代码块. 但糟糕的是, 与C语言不同, JavaScript没有提供相应的块级作用域, 也就是说, 代码块中生命的变量在包含此码块的函数的任何位置都是可见的, 听起来十分拗口, 举个例子就好懂多了.

    for (var i=0; i<5; i++){
      var g = i;
    }
    console.log(g)  //4
    

    for循环中的变量 g 是属于块级代码, 但在全局中却可以调用. 这就是 js 的作用域问题, 与之相对的是C语言的块级作用域. 先看以下代码

    #include<stdio.h>
    int main(){
       int i = 2;
       if (i){
       int j = 10;
    }
    printf(j);
    }
    

    运行这段代码, 编译器会报错. error: ‘j’ was not declared in this scope. 这是由于j是在块级作用域if语句里面的. 所以在全局中式无法使用的.

    因此在JavaScript中要注意这一点, 由于js的这个特性, 我们最好在每个函数的开头部分就声明所有的变量.

  • 自动插入分号

    JavaScript并不强制使用 分号 作为一个语句的结尾, 但当你忘记在语句中使用 分号做为结尾时, 它会自动插入分号来试图修正程序. 注意了, 这个特性可能会出现一些神奇的问题. 例如以下的 return 语句.

    return 
    {
      type: 1,
      msg: "ok"
    }
    

    上面的代码看似返回一个包含元素的对象, 但由于JavaScript自动插入分号的特性, 实际执行的代码已经变成了

    return; 
    {
      type: 1,
      msg: "ok"
    }
    

    这样就导致返回值变成了 undefined, 一定要注意, 上例正确的写法应该把 "{"  放在上一行,也就是

    return {
      type: 1,
      msg: "ok"
    }
    
  • typeof

    typeof 运算符可以用来识别变量或常量的类型.部分情况下它是可以正常判断的, 但是

    type null;     // object
    

    返回的是object 而不是 null ! 这一点千万注意.我们可以用其他的方法来判断一个变量是否为null,最简单的方法就是

    value === null; 
    

    不知道你有没有注意到,由于typeof无法判断object 和null, 因此判断一个变量是否为object时,一定要再三小心.

    typeof value === 'object';    //错误的判断方法
    value && type value === 'object';  // 正确,先判断是否为null
    
  • parseInt

    曾经我在面试的时候遇到过一道经典的JavaScript题,至今让我印象深刻.

    var arr = ['1', '2', '3', '4', '5'];
    var num;
    num = arr.map(parseInt);
    

    很简单的代码,就是把arr数组中的元素转化成整数,理论上来说应该是[1,2,3,4,5], 是的,理论上.然而实际结果确实是[1, NaN, NaN, NaN, NaN].其实原因也不难,就是因为 parseInt 方法其实是可以带两个参数的,第一个参数是要转化成数字的字符串,另一个是指定进制,默认是使用十进制来进行转换,这里举两个例子说明一下.

    parseInt('10', 8);  // 8
    parseInt('10');     // 10
    

    我想你已经知道问题所在了,还不知道?再看看map方法的语法.

    var new_array = arr.map(function callback(currentValue, index, array) {
        // Return element for new_array
    }
    

    也就是说,实际运行过程中数组的索引会被当成parseInt的第二个参数.也就是像下面这样.所以就会出现这样看似不合理的结果了.要避免这种情况也不难,把parseInt 换成Number 就可以了.

    parseInt('1',0);
    parseInt('2',1);
    parseInt('3',2);
    ...
    
  • 浮点数

    这个其实不算坑,只是需要注意一下,先看下面的例子.

    0.1+0.2; // 0.30000000000000004
    

    第一次看到这个结果的时候我也吓了一跳,但其实原因很简单,因为CPU的计算其实都是二进制的,而二进制的浮点数不能正确的处理十进制的小数点,说以会导致计算结果不精准,这不仅是JavaScript的问题,很多编程语言也有同样的问题,例如Python,Java.幸运地是,整数是可以完美处理的.对于有小数点的运算,我们可以指定计算精度来避免这样的问题.

  • NaN

    不得不说这是JavaScript中一个奇葩的变量类型,它表示一个特殊的数量值,它不代表一个数字,当数学表达式无法计算时会用NaN表示,亦或者把非数字形式的字符串转换成数字时.但

    typeof NaN === 'number'; // true
    

    也就是说typeof 是无法辨认数字与NaN的(typeof要你有何用!),更恶心的是

    NaN === NaN; // false
    

    真的无话可说,发明NaN这个关键字绝对是设计者脑抽了.要判断一个变量只能用一个方法;

    isNaN(NaN); //true
    

    延伸一下,由于上面的问题,我们是无法直接用 typeof 方法来判断一个变量是不是数字的.千万要注意,别掉坑里了,我们可以加一个判断.

    typeof value === 'number' && isFinite(value);
    
  • 数组

    JavaScript 中没有真正的数组,JavaScript 中没有真正的数组,JavaScript 中没有真正的数组.重要的事情说三遍.在JavaScript中,一切皆为对象,数组其实是一个有length的对象.这并不都是坏事,由于这个特性,你不必给数组设置维度,也不用担心越界错误(但其实这更容易导致出现隐藏的bug).但这也导致其性能下降的厉害.同理的,你也无法用typeof直接判断一个变量是否为数组(typeof要你有何用!!),你需要检查一个名作constructor的属性.

    typeof value === 'object' && value.constructor === Array;
    
  • 对象

    是的,JavaScript 的对象也是要我们注意的.与Python, Java 不同,JavaScript 中的对象不是通过类来定义的,而是通过原型链.因此,当你创建一个空对象时,该对象绝对不是空的,而是包含了从上一级中继承下来的各种方法与属性,这在有时候会导致问题变得很麻烦.举个例子,你现在在做一个文本分析脚本,首先需要统计一篇文章中每个单词出现的个数,这个时候就要十分小心了.先看下面的代码.

    var text = "To deal with this, you can generate a stack trace in the constructor of the exception object during the throw exception statement. ";
    var words = text.toLowerCase().split(/[\s,.]+/)
    var count = {};
    var word;
    for (var i=0;i<words.length;i++){
      word = words[i];
      if (count[word]){
        count[word] += 1;
      }
      else{
        count[word] = 1;
      }
    }
    

    上面的代码很简单,就是统计一下每个单词出现的次数,但如果查看 count.constructor,你会发现 输出了这个鬼东西:"function Object() { [native code] }1",原因就是上面所说的. count对象继承自Object.prototype.而Object.prototype 中包含着一个constructor的对象.如何避免这个问题呢,我们可以做一个判断,检测成员类型,是数字才进行处理.

  • 其他

    接下来的东西就不细讲了,都是不建议使用的.

    == 这个不用说了吧,大家都知道

    with 别用

    eval 有坑,用前详细查看文档.

    new 尽量别用

    void 别用

相关文章

  • 《JavaScript语言精粹 修订版》 读书笔记

    首发于:segmentfault《JavaScript语言精粹 修订版》 读书笔记 之前看到这篇文章,前端网老姚浅...

  • 读书笔记之JavaScript语言精粹

    作为一个前端开发人员, js的一些坑已经踩了不少, 但这本书总结的非常好, 把精华部分和糟粕部分都非常系统详细的...

  • 2016 读书清单

    技术类javascript权威指南 (未完成)javascript语言精粹(?)javascript设计模式(未完...

  • 前端技术书

    入门级 《JavaScript高级程序设计》 《编写可维护的JavaScript》 《Javascript语言精粹...

  • JavaScript语言精粹

    JavaScript语言精粹 前言 约定:=> 表示参考相关文章或书籍; JS是JavaScript的缩写。 本书...

  • JavaScript语言精粹

    第二章 语法 数字 JavaScript 只有一个数字类型,它在内部被表示为64位的浮点数,和Java的doubl...

  • Javascript语言精粹

    String.slice(start, end) end 均可选,默认为数组长度 参数若为负数时,则从后选取,没有...

  • JavaScript语言精粹

    第1章 精华 JavaScript建立在一些非常优秀的想法和少数非常糟糕的想法之上优秀的想法包括:函数、弱类型、...

  • 《JavaScript语言精粹》

    《JavaScript语言精粹》 第1章 精华 第2章 语法 2.1 空白 ​ 空白可能表现为格式化字符或注释...

  • JavaScript语言精粹

    1、注释/* */包含正则表达式不安全2、Number单一的数字类型,64位浮点数(double),无整数类型,1...

网友评论

      本文标题:读书笔记之JavaScript语言精粹

      本文链接:https://www.haomeiwen.com/subject/purfbxtx.html