# 第一章

使用内置对象创建的变量(不带关键词 new),严格等于字面量

var str1 = "abc";
var str2 = String("abc");
str1 === str2; // true
typeof str1; // string
typeof str2; // string

使用 new 创建的变量,松散等于字面量,不严格等于字面量

var str1 = "abc";
var str2 = new String("abc");
str1 == str2; // true
str1 === str2; // false
typeof str1; // string
typeof str2; // object

访问基本类型的属性时,javascript 引擎会模拟创建一个临时对象来包围基本类型,属性访问之后引擎会立马丢弃这个临时对象。这正是 “基本类型不是对象,但仍可以放问它的一些属性” 的原因。

var str = "abc";
str.length; // 3
str.length = 4; // 为基本类型添加属性,其实是加在了临时对象上。该赋值没有意义,这行代码执行后,临时对象立刻被丢弃。
str.length; // 3

indexOf 使用方式为 str.indexOf(searchValue, fromIndex)searchValue 为要查询的字符串, fromIndex 第 二个参数为起始查询点。 特殊情况:

  1. 如果 searchValue 为空白,即 indexOf() ,searchValue 会被当做字符串 undefined 。
"0123undefined".indexOf(); // 4
  1. 如果 searchValue 为空字符串,结果取决于 fromIndex:
"abc".indexOf(""); // 0 如果fromIndex为空白,或者小于等于0 ,返回 0
"abc".indexOf("", 1); // 1 如果fromIndex 大于 0 且小于等于 str.length,返回 fromIndex
"abc".indexOf("", 10); // 3 如果fromIndex 大于 str.length ,返回 str.length

可以从一个 Date 减去另一个 Date,两者的差值以毫秒返回。然而如果把两个日期相加,结果是第二个日期附加到第一个日期后面的一个字符串。

如果把两个 Date 对象相除,需要把 Date 转换为毫秒值,返回相除的结果。将两个日期相乘,会返回一个非常大的毫秒值。

var firstDate = new Date();
setTimeout(function () {
  var secondDate = new Date();
  console.log(secondDate + firstDate); // Thu Nov 21 2019 16:40:16 GMT+0800 (中国标准时间)Thu Nov 21 2019 16:40:13 GMT+0800 (中国标准时间)
  console.log(secondDate - firstDate); // 近似等于2500
  console.log(secondDate * firstDate); // 2.4785011416546957e+24
  console.log(secondDate / firstDate); // 1.0000000015879815
}, 2500);

lastIndexOf 是从尾部到头部进行搜索,如果给定搜索的起始位置(即第二个参数),则从起始位置向头部进行搜索,返回找到的第一个元素的索引。

var arr = ["a", "b", "c", "a"];
arr.lastIndexOf("a"); // 3 从尾到头进行搜索字母a,首先搜到索引为3的a
arr.lastIndexOf("a", 2); // 0 从索引2位置向头部进行搜索字母a,首先搜到索引为0的a

splice 方法接受到的索引如果为负数,则从末尾开始对数组 / 字符串操作, -n 相当于从倒数第 n 个位置进行操作。如果没有接受到第二个参数,则一直删除到底。

var arr = ["a", "b", "c"];
arr.splice(-2, 1); // ["b"] 从倒数第二个位置即字母b,删除一个元素,一共删除了字母b
arr.splice(-2); // ["b", "c"] 从倒数第二个位置即字母b,一直删除到底,一共删除了b和c

# 第二章

dict 模式:创建拥有一个空的原型的对象,以避免已有的属性可能会搞乱程序。

var obj = {};
var newObj = Object.create(null);
var key = "toString";
console.log(key in obj); // true 解答:toString是一个标准的Object方法
console.log(key in newObj); // false

# 第三章

可以通过字面值函数为函数提供一个名称,但这个名称只能在函数内部用

var fn = function name(){type of name};
fn(); // "function"
name(); // Uncaught SyntaxError 解读:函数名name只能在函数内部访问到

使用 slicecall 可以将类数组或 NodeList 转换为数组。

[].slice.call(arguments);
[].slice.call(NodeList);

# 第四章

继承一个对象的方式: Object.create()apply

function Parent() {
  this.name = "js";
}
Parent.prototype.age = 24;
function Child() {}
//方式一
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
//方式二
function Child() {
  Parent.apply(this, arguments);
}

让方法链化的关键一步是,在方法尾部返回对象(使用该方法的对象)的引用。

function Book() {
  this.setTitle = function (title) {
    this.title = title;
    return this;
  };
  this.setAuthor = function (author) {
    this.author = author;
    return this;
  };
}
var book = new Book();
book.setTitle("js").setAuthor("Jorn");
console.log(book.author); // Jorn

# 第五章

NodeList 唯一可使用的属性为 length,唯一方法为 item。不能直接对 NodeList 使用 Array 方法,比如 push。

DOM 的 style 属性只能获取到内联样式,style 标签以及样式表中的样式,无法通过 .style 方式获取。可以使用 getComputedStyle 去获取元素所有当前生效的样式。

display:none 会从页面布局中完全删除元素,而 visibility:hidden 只是视觉上隐藏了元素,仍然会影响其他元素的布局。

# 第八章

在 JSON 中,如果对象包含其他对象,其他对象会被转换为 JSON 的等价形式。

var obj = { name: "obj" };
var newObj = { name: "newObj", other: obj };
JSON.stringify(newObj); // "{"name":"newObj","other":{"name":"obj"}}"

# 第九章

向 SVG 添加 JavaScript,必须提供 style 属性。并且要把脚本包含在 CDATA 块中,否则 XML 会把 < 当做 XML 而不是脚本对待。

<script type="text/ecmascript">
  <![CDATA[
    var name = 'js';
  ]]>
</script>

访问 svg 元素

<object id="object" data="demo.svg"></object>
<script>
  var object = document.getElementById("object");
  object.onload = function () {
    var svgdoc;
    try {
      svgdoc = object.contentDocument;
    } catch (error) {
      try {
        svgdoc = object.getSVGDocument();
      } catch (error) {
        alert("SVG Not Support");
      }
    }
  };
</script>

Math.round 中间值 (0.5) 向较大数取值,所以 Math.round(-1.5) 为 - 1,而不是 - 2

在获取画布的 imageData 时常常会发生如下错误: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data 增加一个 img.crossOrigin = '' 即可解决这个问题。

video 元素有个 timeupdate 事件,每 200 毫秒触发一次。

虽然 NaN 不等于自身,但是对于使用 NaN 作为键的 Map 对象, NaN 是和自身相等的:

var myMap = new Map();
myMap.set(NaN, "nan");
var key = Number("not a number");
console.log(myMap.get(key)); // 'nan'

使用数组作为键的 Map 对象,必须使用完全相同的键才能获取到响应的键值:

var arr = [1, 2];
var arr2 = arr;
var myMap = new Map();
myMap.set(arr, "12");
console.log(myMap.get([1, 2])); // undefined
console.log(myMap.get(arr2)); // '12'

# 第十二章

通用模块定义 UMD

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global.moduleName = factory());
}(this, function () {
  'use strict';
  // TODO
}

某个 package.json 文件中,用 npm remove 命令移出 dependencies(或 devDependencies)中的最后一项,属性 dependencies 并不会被一并删除,只是将其设为一个空值。

"dependencies":{}

# 第十三章

Worker 线程的一个缺点,就是并不是所有的内建对象或功能都能在所有的浏览器中可用。比如在旧版本的 Firefox 中,异步的 FileReader 不会在 Worker 线程中工作。

# 第十四章

Shadow DOM,即这部分 DOM 默认与外部 DOM 隔离,内部任何代码都无法影响外部。

Web Component https://jsfiddle.net/zhaohd/vfbnLeaz/

# 第十五章

要使用 GET、POST 或 HEAD 之外的一个方法,必须对你的请求预检(preflight)。