Effective JavaScript读书笔记(一)

做为一个前端新人,多读书读好书,夯实基础是十分重要的,正如盖楼房同样,底层稳固了,才能越垒越高。从开始学习到如今,基础的读了红宝书《JavaScript高级程序设计》,犀牛书《JavaScript权威指南》,特别是红宝书,是把我领进js领域的一本书。如今到了进阶阶段(可能红宝书还会回去继续翻),准备开始读《Effective JavaScript》,刚拿到手,很薄的一本书,也把读书笔记整理下来,但愿养成一个良好的读书习惯。前端

让本身习惯JavaScript

了解JavaScript的版本

目前主流JavaScript版本任然是ES5,在ES5开始引入严格模式正则表达式

use strict;//在文件头或者函数体顶部使用,就是严格模式

通常来讲,咱们若是想编写一个通用型插件,都须要使用严格模式来进行开发,可是在使用严格模式开发时会出现一个问题,工程前后引入两个文件file1.js和file2.js,file1.js使用的严格模式进行开发,file2是非严格模式,那么下面的代码会出问题。编程

<script src="file1.js" />
<script src="file2.js" />
// 这么引入两个文件,file2也会按照严格模式运行,那么若是file2.js出现了非严格模式的行为,程序就会报错
所以,在严格模式下开发通用插件的时候须要注意这个问题

解决办法:使用当即执行函数IIFE进行开发。浏览器

(function(){
    'use strict';
    function foo(){
        //你的插件内容
    }
})();

理解JavaScript浮点数

JavaScript中只有一种数值类型,不管是整数仍是浮点数,都被表示为Number类型,可使用typeof关键字查看它们。安全

typeof 17.2;//'number'
typeof 26;//'number'

JavaScript之中全部的数字类型都是双精度浮点数,整数也能够用双精度浮点数来表示,如JavaScript之中所能表示的整数范围是(2e-53~2e53).函数

JavaScript中的浮点数是不精确的

其中最著名的例子就是:0.1+0.2;//0.30000000000000004学习

JavaScript中的数字类型在表示浮点数上不必定精确,使用时要慎重编码

小心隐式的强制转换

终于到了JavaScript强大的饮食转换了,先来看一个简单的例子spa

(([][[]]+[])[+!![]]+([]+{})[!+[]+!![]]).toUpperCase();

猜猜上面的代码的结果是什么?答案是:NB,没错,JavaScript就是这么NB。根本绝不相关的东西,这也正是体现了JavaScript隐式转换的强大之处,感兴趣的能够百度一下上面为何会出现这样的结果。插件

隐式转换的一些原则

    • 布尔型与数字类型相互转换
      其中,true对应1,false对应0.

      3+true; // 4
      while(1){ //至关于while(true)
          //无限循环
      }
    • 字符串与数字相互转换
      在这里不得不提的就是JavaScript对运算符加号“+”的重载,JavaScript的加号不只能够进行数字相加,还能够进行字符串的拼接工做,还能够进行数字与字符串的隐式转换工做。例以下面的几行代码

      2 + 3; // 5
      "hello" + " world";// "hello world"
      2 + "3"; // "23"
      // 这里还有个十分重要的,数字字符串以前若是只存在一个加号,会将字符串隐式转换成数字类型
      +"3";// 3
      +"3fsdf"; //NaN
      1+(+"3");// 4,必须有括号,不然JavaScript会把两个加号编程自加运算,从而报错表达式不合法
      // 须要注意的是,对于加法来讲,隐式转换的优先级字符串高于数字类型,而位运算和乘法除法运算数字类型高于字符串类型
      "17" * 3; // 51
      "8" | "1";// 9
    • 强制转换的隐藏错误

      null会在运算中隐式转换成0
      一个未被定义的变量(undefined)会被隐式转换成浮点类型的NaN。
      //关于NaN的几点注意
      var x = NaN; x === NaN;//false
      isNaN(NaN);// true
      //可是isNaN对于其余不是浮点类型的数来讲,也会隐式转换成NaN,所以这个API存在问题
      isNaN('string');//true
      isNaN(undefined);//true
      isNaN({});//true
      //所以若是想判断是否是正正的NaN,咱们能够写一个函数来判断
      function isReallyIsNaN(number) {
          return number !=== number; //利用NaN不等于自身这一特性
      }
    • 对象的隐式转换
      默认来讲,对象也会被隐式转换成字符串

      "the Math object: "+ Math;//"the Math object: [object Math]",Math对象被隐式转换为字符串
      // valueOf方法是真正为那些表明数值的对象(Number)而设计的
          var obj = {
          toString: function() {
              return '[object Object]';
          },
          valueOf : function() {
              return 26;
          }
      }
      'the obj true value is:'+obj;//'the obj true value is:26',

      对象的valueOf才是真值

    • 真值运算
      JavaScript中的逻辑运算if、||和&&理论上是能够接受任何值的,由于JavaScript中
      全部类型都会在逻辑运算中转换成布尔值

      JavaScript中有7个假值:false、0,-0、""、NaN、null、undefined

      因为数字和字符串可能为假值,因此,使用针织运算检查函数参数或者对象属性是否已经存在不是绝对安全的。

      function point(x){
          if(!x){
              return 26;//若是x为假值,不传或者传入0,函数都会返回26
          }
      }
      point(0);//x:26
      //可是,传入0这个值是彻底有可能的,因此这种判断形势是不正确的
      function point(x){
          if(typeof x === 'undefined'){
              return 26;
          }
          //或者使用if(x === undefined)来判断也能够
      }

    原始类型优于封装类型

    JavaScript对象拥有六个原始值基本类型: 布尔值,数字,字符串,null,undefined和对象。

    须要注意的是,使用typeof对null判断获得的结果是'object',ECMAScript标准描述null是一个独特的类型

    建立原始类型与建立基本类型

    //建立一个String对象,内部封装一个字符串值
    var s = new String("hello");
    s + ' world';// 'hello world'
    //建立一个原始类型
    var str = 'string';
    //封装类型本质是一个对象,原始类型才是基本类型,可使用typeof来查看
    typeof s;// 'object'
    typeof str;// 'string'
    //因为封装类型自身是一个对象,所以即便内部封装的值相同,两个对象也是不相等的
    var s1 = new String('string');
    var s2 = new String('string');
    s1 === s2;//false
    s1 == s2;//false

    整体来说,通常不须要使用封装类型来代替基本类型,由于基本类型不管是从声明仍是使用都较为方便。并且,基本类型自己是没有任何方法的,不过能够隐式转换成String对象来执行其内部方法:

    var s = 'hello';//基本类型
    s.toUpperCase();//HELLO,将s隐式转换成String对象

    【注】隐式封装的类型有一点须要特别注意:每一次隐式封装都会产生一个新的String对象,原来的对象会被抛弃,也就是说新产生的隐式封装对象生命周期就是所在行代码执行完成。

    'string'.value = 26;
    'string'.value;//undefined
    第二行代码隐式封装造成了新的String对象,新的String对象内部没有value这个属性值,所以是undefined

    对JavaScript原始类型值设置属性是没有意义的

    避免对回合类型使用 == 运算符

    因为JavaScript隐式转换的存在,所以,在使用 == 运算符的时候,有时候可能不会获得咱们所预期的结果。

    '1.0e0' == { valueOf: function(){ return true } };
    //结果是true,由于右侧valueOf结果是true,会被隐式转换成数字1,根据隐式转换法则,左侧字符串也会被隐式转换成1,所以比较是相等的。
    // 使用==运算符比较时一些特殊状况
    null == undefined;//true,这种状况永远是true
    null/undefined ==
    string/number/boolean;//false,这种状况永远是false
    string/number/boolean == string/number/boolean;// 将原始类型转换为数字进行比较
    string/number/boolean == Date对象;// 先将原始类型转化成数字,再将date类型转化成原始类型(优先尝试toString,其次尝试valueOf)
    string/number/boolean == 非Date对象;// 先将原始类型转化成数字,再将date类型转化成原始类型(优先尝试valueOf,其次尝试toString)

    // 关于Date对象比较问题

    var date = new Date('1993/07/11');
    date == '1993/07/11';//false

    这是由于Date对象调用toString方法以后转换的不是咱们所熟知的字符串形式。

    在浏览器中调用date.toString(),结果是"Sun Jul 11 1993 00:00:00 GMT+0800 (中国标准时间)"

    //将Date类型字符串转换成咱们定义格式的字符串
    function toYMD(date){
        var y = date.getYear() + 1,
            m = date.getMonth() + 1,
            d = date.getDate();
        return y + '/'
             + (m < 10 ? '0' + m : m) + '/'
             + (d < 10 ? '0' + d : d);
    }
    toYMD(new Date('1993/07/11')); //"1993/07/11"

    在比较的时候,最好使用严格相等运算符 ===,这是一个良好的习惯

    了解分号插入的局限

    JavaScript语法对于分号没有硬性的规定,其语言机制自身会自动添加分号而区分开语句,了解分号插入的规则,对于提升JavaScript代码的严谨性有着巨大的帮助。

    分好仅在 } 标记以前、一个或多个换行符以后和程序的输入结尾被插入

    换而言之,咱们只能够在一行、一个代码块和一段程序结束的地方省略分号,其余任何地方省略分好都有可能出现错误。

    function foo1(r){ r += r; return r };//合法
    function foo2(r){ r += r return r };//不合法

    分好仅在随后的输入标记不能被解析时插入

    换句话说,分好是JavaScript为咱们提供的一种错误校订机制

    a = b
    (f());
    // 上面这段代码会被解析成
    a = b(f());//这是一条合法语句
    a = b
    f();//下面这段代码会被解析成两条独立的语句,由于 a = b f()是不合法的语句

    换句话说,其实JavaScript只是为咱们机械化的解决了语法问题而已,若是解析不合法,就会为咱们经过插入分号来解决问题,可是,可能不是咱们所预期的,所以,规范化的代码才是重中之重,尽可能不要省略分号。

    另外一个比较重要的状况是:return语句,在return关键字和其可选参数之间必定不能够包含换行符。

    return {}; //一条语句,返回一个空对象
    return 
    {}; 
    //上面语句等价于
    return ; 
    {}
    ;
    也就是会自动在return后面的换行符前插入一个分号

    另一种特殊状况就是++运算符和--运算符

    a
    ++
    b;
    //会被解析成
    a;
    ++b;

    在return、throw、break、continue、++、--的参数以前不能够换行

    分号不会做为分隔符在for循环空语句的头部被自动插入

    也就是说,for循环体内必须显式的包含分号,不然会出错

    for(var i = 0, total = 1 // 解析出错
        i < n
        i++)

    视字符串为16位的代码单元序列

    几种流行的Unicode编码:utf-八、utf-1六、utf-32

    • JavaScript字符串是由16位代码单元组成,而不是由Unicode代码点组成

    • JavaScript使用两个代码单元表示2e16及以上的Unicode代码点。这两个代码单元被称为代码对。

    • 代理对甩开了字符串元素计数,length、charAt、charCodeAt方法以及正则表达式模式受到了影响

    相关文章
    相关标签/搜索