写在前头 Link to heading

还是得要膜拜一下廖雪峰大神, 原文都在这了. 这篇帖子只是单纯的笔记整理

数据类型 Link to heading

  1. number: 不区分整数和浮点数
  2. 字符串
  3. 布尔值: true/false

比较运算符, == vs. === Link to heading

javascript 允许对任意数据类型作比较

false == 0 // true
false === 0 // false
  • == 会自动转换数据类型再比较 (不推荐使用)
  • === 不会转换数据类型 (应该坚持使用)
  • NaN 与所有值(包括自己都不同), 只有通过 isNaN() 才能判断.
  • 比较浮点数时候, 要计算他们的绝对值是不是小于某个阈值

null vs. undefined Link to heading

  • null, 空. 它不等于0, 也不等于''.
  • undefined 表示值未定义, 只有在未规定 return 值的时候/object 中没有这个 prop 时候,会返回undefined, 其他时候我都会用 null.

javascript 中的对象 Link to heading

unsorted key-value pair

strict模式 Link to heading

JavaScript在设计之初,为了方便初学者学习,并不强制要求用var申明变量。这个设计错误带来了严重的后果:如果一个变量没有通过var申明就被使用,那么该变量就自动被申明为全局变量

为了避免这一缺陷,所有的JavaScript代码都应该使用strict模式

字符串 ES6 新规范 Link to heading

  • 反引号’`’: 反引号括起来的多行字符串可以保留多行
  • 串起来字符串: 通过${}实现
  • javascript 中字符串是可以 slicing 的

for…of… Link to heading

for … in … 是个历史遗留问题, 如果给array添加新的属性会得到一个被扩展的 array (手动滑稽)

for … of … 修复了这个问题.

当然, 更好的方法是使用 iterable 自带的 forEach() 方法

有人说 for … in … 用于 objects.

for … of … 用于 string/array.

函数定义和调用 Link to heading

  • 一旦执行到 return, 函数就会返回; 如果没有 return, 函数返回的结果为 undefined
  • javascript 允许传入任意个参数而不影响调用

this 与控制 this 指向 Link to heading

this 指向的是 当前 的对象 (被赋值给了谁, 就指向谁; 如果没有赋值, 指向 undefined)

当用了 strict, 那么 this 指向当前函数, 如果没用 strict, this 指向 window

apply 与 装饰器 Link to heading

apply(<需要指向的参数>, <传入的参数/类型为array>) 可以把 this 指定到一个对象

函数作为返回值 - 闭包 Link to heading

顾名思义, 把函数作为结果值返回, 我们来看以下例子:

function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // type of f  = function sum()

只有当调用函数f()时候, 才真正求和

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

此处参考 python cheating sheet 闭包

[我的补充]: 闭包就是普通函数, 没有区别, 当作用域是全部的时候, 那么函数可以读到全部作用域的值.

创建匿名函数并立刻执行的语法 Link to heading

(function (x) {
    return x * x;
})(3); // 9

闭包的常见用途 Link to heading

  • 延后执行函数 (lazy_sum)
  • 闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来.

如果忘了闭包的话, 那么点点下面的连接复习一下 Link to heading

连接

javascript 原型链 Link to heading

var arr = [1, 2, 3];

其原型链是

arr ----> Array.prototype ----> Object.prototype ----> null

创建对象 Link to heading

当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined.

new的用处 Link to heading

在 javascript 中, 可以用 new 关键字来调用一个函数并返回对象. 如果不写 new, 那么这个函数就是普通函数, 如果没有规定 return, 那么就会返回 undefined. 如果写了 new, 那么 this 指向新创建的对象, 并默认返回 this.

桥接函数 F Link to heading

如果有以下原型链,

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Object.prototype ----> null

如果现在,我们要基于Student扩展出PrimaryStudent,可以先定义出PrimaryStudent, 就必须有如下的原型链

new PrimaryStudent() ----> PrimaryStudent.prototype ----> Student.prototype ----> Object.prototype ----> null

怎么弄呢?

// Student 构造函数
function Student(props) {
    this.name = props.name || 'Unnamed';
}

Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

// PrimaryStudent构造函数:
function PrimaryStudent(props) {
    Student.call(this, props);
    this.grade = props.grade || 1;
}

// 空函数F:
function F() {
}

// 把F的原型指向Student.prototype:
F.prototype = Student.prototype;

// 把PrimaryStudent的原型指向一个新的F对象,F对象的原型正好指向Student.prototype:
PrimaryStudent.prototype = new F();

// 把PrimaryStudent原型的构造函数修复为PrimaryStudent:
PrimaryStudent.prototype.constructor = PrimaryStudent;

// 继续在PrimaryStudent原型(就是new F()对象)上定义方法:
PrimaryStudent.prototype.getGrade = function () {
    return this.grade;
};

// 创建xiaoming:
var xiaoming = new PrimaryStudent({
    name: '小明',
    grade: 2
});
xiaoming.name; // '小明'
xiaoming.grade; // 2

// 验证原型:
xiaoming.__proto__ === PrimaryStudent.prototype; // true
xiaoming.__proto__.__proto__ === Student.prototype; // true

// 验证继承关系:
xiaoming instanceof PrimaryStudent; // true
xiaoming instanceof Student; // true

如果把继承这个动作用一个inherits()函数封装起来,还可以隐藏F的定义,并简化代码:

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

promise vs. callback Link to heading

callback Link to heading

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

callback 的出现是因为 javascript 是单线程执行, 所以所有的网络操作, 浏览器事件都必须是 异步执行, 因为异步是非阻塞的. 由于 javascript 对耗时的操作时间不确定, 所以异步成了必然选择.

javascript 引擎中只有一个主线程, 负责解释代码.

但是, 还有其他线程存在, 这些线程不管在 js 引擎内还是引擎外. 比如 ajax 线程. 我们把那些都叫工作线程.

异步是回调/callback 的基础, 回调多了, 代码看上去不好理解, 这就叫回调地狱.

promise Link to heading

A promise is an object that wraps an asynchronous operation and notifies when it’s done. This sounds exactly like callbacks, but the important differences are in the usage of Promises.

原文在这里

promise 解决了回调地狱的问题, 原来要 callback 的东西, 我们现在直接用 then 连接在一起, error 用 catch 来解决.

当我们再函数中返回了一个 promise 的时候, 我们再 call 这个函数的时候自然就有了 thencatch 方法.

async and await Link to heading

async keyword before a function has two effects:

  1. make it always return a promise
  2. allow to use await in it

The await keyword before a promise makes javascript wait until that promise settles, and then:

  1. If it is an error, the exception is generated, same as if throw error were called at that very place.
  2. otherwise, it returns the result, so we can assign it to a value.

但是好像大家并不是特别鼓励用 await.

… easiest way to solve that is to group concurrent async calls with Promise.all –solstice333

destructuring - ES6 Link to heading

destructing 可以非常智能的按照顺序取出你想要拿出的variables. 不够直观? 看个例子

var [first, second, third] = someArray;

是不是看着有点眼熟, 在哪见过? 没错, python 也用 destructuring. 但是 python 和 javascript 的 destructuring 是有一点不一样的.

d = dict(a=1,b=2,c=3)
a, b = [d[k] for k in ('a','b')]

总之, 记得 python 也有 destructuring 就好了.

回到这一小节的正题:

array and iterables Link to heading

[ variable1, variable2, ..., variableN ] = array;
var [ variable1, variable2, ..., variableN ] = array;
let [ variable1, variable2, ..., variableN ] = array;
const [ variable1, variable2, ..., variableN ] = array;

object Link to heading

var robotA = { name: "Bender" };
var robotB = { name: "Flexo" };

var { name: nameA } = robotA;
var { name: nameB } = robotB;

destructuring 的实际用处 Link to heading

  • 不用让 API user 记住 param 的顺序, API 使用更加友好
function removeBreakpoint({ url, line, column }) {
  // ...
}
  • 传入 default config
jQuery.ajax = function (url, {
  async = true,
  beforeSend = noop,
  cache = true,
  complete = noop,
  crossDomain = false,
  global = true,
  // ... more config
}) {
  // ... do stuff
};
  • importing names from module
const { SourceMapConsumer, SourceNode } = require("source-map");
import React, { Component } from 'react'

credit to Link to heading