📖 JavaScript 阅读摘抄

JavaScript 模式

JavaScript 模式, Stoyan Stefanov, 中国电力出版社, 2012

  • 只有五种基本类型不是对象: 数值类型、字符串类型、布尔类型、空类型和未定义类型.
  • 原型是一个对象, 并且创建的每一个都会自动获取一个 Prototypes 属性, 该属性指向一个新的空对象.
  • 任何变量, 如果未经声明, 就是全局对象所有.
  • 使用 var 创建的全局变量不能删除; 不使用 var 创建的隐含全局变量可以删除.
  • 只是用一个 var 在函数顶部进行变量声明是一种非常有用的模式.
  • JavaScript 允许在函数的任一地方声明多个变量, 无论在哪里声明, 效果都等同于在函数顶部进行声明. 这就是所谓的提升.
  • for 循环

      // 第一种
      // 每次循环都需要访问数据长度
      for (var i = 0; i < myarray.length; i++){
          // 操作
      }
    
      // 第二种
      var i, myarray = [];
      for (i = myarray.length; i--) {
          // 操作
      }
    
      // 第三种
      var myarray = [],
          i = myarray.length;
      while (i--) {
          // 操作
      }
    
  • for-in 循环

      for (var i in man){
          if (man.hasOwnProperty(i)) {
              console.log(i, ":", man[i]);
          }
      }
    
  • 不要增加内置的原型
  • switch 模式(case 后面加 break)

      switch (inspect_me) {
          case 0:
              result = "zero";
              break;
          case 1:
              result = "one";
              break;
          default:
              result = "unknown";
      }
    
  • 及时对象初始化模式

      ({
          maxwidth: 600,
          maxheight: 400,
    
          gimmeMax: function () {
              return this.maxwidth + "x" + this.maxheight;
          }
    
          init: function () {
              console.log(this.gimmeMax);
              // ....
          }
      }).init();
    
  • 模块模式

      MYAPP.utilities.array = (function () {
          // 依赖
          var uobj = MYAPP.utilities.obejct;
          // 私有属性 ...
          // 私有方法 ...
          isArray = function () {...},
          inArray = function () {...};
          // 揭示共有 API
          return {
              isArray: isArray,
              indexof: inArray
          }
      })
    
  • 各种设计模式: 单体模式, 工厂模式, 迭代器模式, 装饰者模式, 策略模式, 外观模式, 代理模式, 中介者模式, 观察者模式

编写可维护的 JavaScript

编写可维护的 JavaScript, Nicholas C. Zakas, 人民邮电出版社, 2013

  • ECMAScript5 引入了“严格模式”, 在代码中加入 "use strict"; 以严格模式执行代码. 严格模式下使用未声明变量或 with 等不规范的语句会报错. 对于需要多个文件拼合, 建议将 "use strict"; 放置于函数内顶部, 避免其中一些文件使用了非严格模式而可能报错. 严格模式若置于函数外部, 整个文件都将采用严格模式执行.
  • 将 JavaScript 从 CSS 中抽离, 避免使用 CSS 表达式, 比如

      .box {
          width: expression(document.body.offsetWidth + "px");
      }
    
  • 将 CSS 从 JavaScript 中抽离, 不直接修改 DOM 元素的 style 属性, 通过 CSS 类名的操作实现样式更改.

      /* 样式 */
      .reveal{
          color: red;
      }
    
      /* javascript */
      // 好的写法 - 原生方法
      element.className += "reveal";
    
      // 好的写法 - HTML5
      element.classList.add("reveal");
    
      // 好的写法 - YUI
      Y.one(element).addClass("reveal");
    
      // 好的写法 - jQuery
      $(element).addClass("reveal");
    
      // 好的写法 - Dojo
      dojo.addClass(element, "reveal");
    
  • 将 JavaScript 从 HTML 中抽离, 不直接将事件写于 HTML 中

      <!-- 不好的写法 -->
      <button onclick="doSomthing()" id="action-btn">Click Me</button>
    
      // 好的写法
      var btn = document.getElementById("action-btn");
      btn.addEventListener("click", doSomthing, false);
    
  • 将 HTML 从 JavaScript 中抽离

    • 从服务器加载, 比如采用 Ajax, 从服务器加载内容.
    • 客户端模板, 在 HTML 中预留 “插槽” (比如注释语句,或既定格式的字符串写入标签属性中), 然后通过 JavaScript 替换.
  • 避免使用全局变量(尽可能少的使用全局变量, 使用单一变量)

      var MaintaniableJS = {};
    
      MaintainableJS.Book = function(title) {
          this.title = title;
          this.page = 1;
      }
    
  • 零全局变量, 实现方法是使用一个立即执行的函数调用并将所有脚本放置其中

      (fucntion(win) {
          "use strict";
          var doc = win.document;
          // 在这里定义其他变量
          // 其他相关代码
      }(window));
    
  • 不要分发事件对象, 一个事件对象包含很多和事件相关的额外信息, 而一般只用到其中的一部分.

      // 好的写法
      // 获取位置并定位
      var MyApplication = {
          handleClick: function (event) {
              // 假设事件支持 DOM Level2
              event.preventDefault();
              event.stopProgation();
    
              // 传入应用逻辑
              this.showPopup(event.clientX, event.clientY);
          },
    
          showPopup: function(x, y) {
              var popup = document.getElementById("popup");
              popup.style.left = x + "px";
              popup.style.top = y + "px";
              popupclassName = "reveal";
          }
      };
    
      addListener(element, "click", function(event) {
          MyApplication.handleClick(event);
      });
    
  • 阻止修改: 锁定对象

      var person = {
          name: "Nicholas"
      };
      console.log(Object.isExtensible(person));//true
      Object.preventExtensions(person)
      console.log(Object.isExtensible(person));//false
      person.age = 25; // 严格模式下会报错
      console.log(Object.isSealed(person));//false
      Object.seal(person);
      console.log(Object.isSealed(person));//true
      console.log(Object.isFrozen(person));//false
      Object.freeze(person);
      console.log(Object.isFrozen(person));//true
    
  • 基本目录结构

    • _build_ 用来放置最终构建后的文件, 理想情况下这个目录不应该提交.
    • _src_ 用来放置源文件, 包括用来进行文件分组的子目录.
    • _test_ 用来放置测试文件

JavaScript 启示录

JavaScript启示录, Cody Lindley, 人民邮电出版社, 2014

  • 原始值不是对象
  • 函数总有返回值
  • call 传输多个分开的参数, apply() 传递多个参数组成的数组
  • 创建函数时, 系统会 (在后台) 创建一个名为 this 的关键字, 它链接到运行该函数的对象.
  • 除 this 和 arguments 以外的所有变量都遵循词法作用域规则.
  • 用新对象替换 prototype 属性会删除默认构造函数属性.

Effective JavaScript: 编写高质量 JavaScript 代码的 68 个有效方法

Effective JavaScript, David Herman, 机械工业出版社, 2014

  • 只有 NaN 不等于它自身,可以用这个特点检测是否是 NaN, 而不用 isNaN 函数
  • 使用立即调用的函数表达式创建局部作用域

      (function(){console.info("code here");})();
    
  • C.prototype 用于建立由 new C() 创建的对象原型, Object.getPrototypeOf(obj) 是 ES5 中用来获取 obj 对象的原型对象的标准方法, obj._proto_ 是获取 obj 对象的原型对象的非标准方法.
  • 在原型中存储方法, User.prototype.method = function(){}.
  • 在闭包中存储私有数据.

JavaScript 性能优化

JavaScript 性能优化:度量、监控与可视化, Tom Barker, 机械工业出版社, 2014

浏览器内核(渲染引擎, rendering engine): Firefox(Gecko), Chrome(WebKit, Blink), Safari(WebKit), IE(Trident), Opera(Presto, WebKit, Blink).

浏览器 JavaScript 引擎: Firefox(SpiderMonkey), Chrome(V8), Safari(JavaScriptCore), IE(Chakra), Opera(Carakan)

主要是讲工具或者自己构建工具来分析 JavaScript 的性能。一个基本流程是利用 WebPagetest 的 API,通过 PHP 收集数据,然后用 R 分析和可视化数据。后面再升级了一下这个工具,添加了浏览器对象来获取数据 (window.performance)。还介绍了日志工具… 总之这本书是关于分析性能工具的书.

Web 性能实践日志

Web 性能实践日志, Stoyan Stefanov, 人民邮电出版社, 2014

  • 大而化小, 同类相聚, 让缓存时间更长, 让加载更智能.
  • 将资源放入 localStorage, 同时考虑 localStorage 本地读取性能