1. 1. JS使用环境
由于更先进的JvaScript engines和frameeworks( Node, Apache Cordova, Ionic, and Electron)的发明,JS几乎可以做任何事
1.1. JS是更为面向函数的(functionally oriented)
- 函数可被视为对象
- 可以被常量创建
- 被变量引用
- 被当作函数变量传递
- 被作为返回值返回
- 支持函数闭包
- 当一个函数主动地保存一个外部变量就可将这个函数称为闭包
- 作用域
- JS不像C++那样有块级(block-level variables )作用域
- 只用全局和函数两种级别的作用域
- 基于原型的面向对象(Prototype-based object orientation)
- 区别于基于类的(Class-based)
- 最主要的区别:Class中,类和实例不同;Prototype中,凡对象均为实例
- 区别于基于类的(Class-based)
1.2. JS需要关注的特性
- 生成器(generator)
- 类似Python,即一个可以在两个请求之间暂停的函数
- 约定(promise)
- 更好地控制异步代码
- 代理(proxy)
- 控制对特定对象的访问
- 高级数组方法(advanced array methods)
- 哈希(map)
- 正则式(regular expression)
- 模块(module)
1.3. JS演进
- ECMAScript委员发布新版本,比如(ES7/ES2016)
- 注意这只是标准的更新,要实际运用得等到JS引擎更新才行
- 但不同于Python,js引擎是由用户浏览器决定的
- 所以需要转译器(transpiler,又称源代码到源代码编译器source-to-source compile,翻译器transcompiler)
以某种编程语言的程序源代码作为输入,生成以另一种编程语言构成的等效源代码的编译器
For example, converting C++ code to C code will involve a transpiler.
- 在这个语境下,是指将高端的JS代码转换为等效兼容的JS代码
1.4. 浏览器工作原理

The DOM is a structured representation of the UI of a client-side web application
- 根据DOM-JS来说,DOM本质就是将HTML(Document)文本理解为对象(Object),并以节点树的方式组织(Model)。
1.5. 调试、测试、性能分析
调试
- dev tool
测试 - assert
性能分析 - console对象内置方法
time
和timeEnd
1 | console.time("begin") |
- 单步操作太快所以用循坏来增加时间,以体现差异
- console对象的结果显示在控制台上
1.6. JS跨平台
- 桌面级应用
- NW.js
- Electron
- 移动应用框架
- Apache Cordova
- 服务端应用
- Node.js
2. 2. 在运行时构建页面
How many events can a web application handle at once?
2.1. 浏览器周期

更为宏观的看:浏览器本质上是一个GUI应用,所以它的生命周期也和其他GUI应用一样分为两步
- 页面加载,绘制用户界面(UI)
- 进入事件循环,并开始调用事件句柄(handler)

2.1.1. 页面加载阶段
- 解析HTML并构建DOM
- 执行JS代码
在页面加载阶段,这两步骤可反复横跳

2.1.1.1. 解析HTML并构建DOM
HTML vs DOM
- HTML相当于DOM初始化页面的蓝图(blue print)
- 浏览器再构建DOM时可以对蓝图中的错误进行纠正

The intention of the head element is that it isused for providing general page information: for example, the page title, characterencodings, and external styles and scripts. It isn’t intended for defining page content,as in this example. Because this is an error, the browser silently fixes it by constructingthe correct DOM
2.1.1.2. 执行JS代码
在解析HTML时,当遇到script元素时,浏览器停止DOM构造并开始执行JS代码
- 浏览器通过全局对象来提供API
windows
对象作为一个全局对象的同时,还可以访问其他全局对象、全局变量以及APIwindows
对象最重要的属性是document
2.1.2. 事件处理
页面加载阶段完成后,进入时间处理阶段
- GUI应用需要应对各式各样的事件,比如鼠标点击、键盘键入等
- 浏览器是单线程执行的,因此需要事件队列
queued up as they occur and are processed as the single thread of execution allows

- 注意事件的来源是多样的:比如client-side,鼠标点击;也可以是server-side,比如Ajax事件
- 两者共同被放入同一队列中
- web应用未响应可能就是卡壳在上一个事件处理线程上
- 注意,将事件放入队列这一浏览器机制是独立于 页面加载 与 事件循环 两个阶段的
2.1.2.1. 异步
event类型
- 浏览器事件
- 网络事件
- 用户事件
- 计时器事件
异步
- 即双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送
2.1.2.2. handle句柄 vs handler处理函数
- A
handle
is an abstract reference to a resource. Handle是对某个资源的抽象引用。 - A
handler
is an asynchronous callback subroutine. Handler则是一个异步的回调函数(子程序)event handlers
are functions that we want executed whenever a particular event occurs
2.1.2.3. 注册
为了调用事件处理函数,我们需要在事件发生时通知浏览器,即event-handler registration
- 将函数赋值给对象的属性
windows.onload=function(){}
- 用内置
addEventListener
方法
1 | document.body.addEventListener("mousemove", function(){}); |

3. 3. 头等函数
First-class Function
当一门编程语言的函数可以被当作变量一样用时,则称这门语言拥有头等函数。例如,在这门语言中,函数可以被当作参数传递给其他函数,可以作为另一个函数的返回值,还可以被赋值给一个变量
3.1. 作为头等对象的函数
通过字面量
{}
创建1
function test(){};
赋值给变量
1
2
3
4
5var test={};
var test = function (){};
test.push(function(){});能够参数传递,或作为返回值
能够具有属性
1
2
3
4
5var test={}
test.name=abc;
var test=function(){};
test.name=abd;正因如此,头等函数可被视为对象的一种
3.1.1. 回调函数
一个在将来会被调用的函数被称为回调函数,无论它之后是被其他函数还是浏览器本身调用
回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过参数将函数传递到其它代码的,某一块可执行代码的引用
- 特征:通过参数将函数传递到其它函数中

1 | asserts( |
- 匿名函数作为回调函数
- 回调函数相对于主调函数既可以是同步的(比如上例),也可以是异步的(比如在某一特定event下才被调用)
3.2. 作为对象的函数
3.2.1. 如何存储函数
- 最为基础的方法:将函数们存为数组然后循环遍历去重
- 更为高阶的方法:利用函数属性
- 本质上来说也就是从o(n)的数组换成o(1)的字典

属性: 值
,定义对象的属性- 这段代码相当于初始化一个id函数的id属性并纳入cache中存储
3.2.2. 自记忆化(self-memoizing)的函数
- 相当于生成器
memoization is the process of building a func-tion that’s capable of remembering its previously computed values.
- 减少重复计算
1 | function isPrime() { |
==
vs===
==
: 值等如果两个操作数不是同一类型时,js会尝试将其转化为合适的类型,然后进行比较
===
: 值与类型皆等当左右两个操作数不是同一类型时,js不会转换其类型
- 首先检查函数
isPrime
是否存在answers
属性,没有则创建 - 由于
cache
是函数本身的属性,因此只要函数还存在那么它就还存在 return isPrime.answers[value] = prime;
:从右到左赋值,然后返回isPrime.answers[value]
这么做的代价:
- 将缓存与业务逻辑绑定在了一起
3.3. 定义函数的方式
- 函数声明(Function Declaration)
- 定义命名的函数变量,而无需给变量赋值
function myFun(){ return 1;}
- 定义命名的函数变量,而无需给变量赋值
- 函数表达式(Function Expression )
- 将函数定义为表达式语句(通常是变量赋值)的一部分。通过 Function Expression 定义的函数可以是命名的,也可以是匿名的。
For function declarations,the function name is mandatory, whereas for function expressions it’s completelyoptional.
var a = function() {return 3;}
- 将函数定义为表达式语句(通常是变量赋值)的一部分。通过 Function Expression 定义的函数可以是命名的,也可以是匿名的。
- 箭头函数(Arrow functions ,或称lambda函数)
- ES6加入
myArg => myArg*2
- ES6加入
- 函数构造器(Function constructors)
new Function('a', 'b', 'return a + b')
- 生成器函数(Generator functions)
- ES6加入
- 能退出并再进入,同时在这一过程中保持函数变量的值
function* myGen(){ yield 1; }
3.3.1. 函数声明

3.3.2. 函数表达式

- 函数表达式定义的函数可以匿名:因为可以不用以显示的函数名字的方式来调用
3.3.2.1. 即时函数(IMMEDIATE FUNCTIONS)
1 | // 标准函数调用 |
- 调用括号左侧的表达式不一定是一个简单的标识符(Identifier),它可以是任何等效于函数的表达式。例如,指定一个等效为函数的表达式的简单方法是使用一个函数表达式
- 注意到上图中单元运算符不需要额外加括号来做区分
3.3.3. 箭头函数
- 从某种意义上说,箭头函数即是对函数表达式的简化
1 | var values = [0, 3, 2, 5, 7, 4, 8, 1]; |
=>
又称胖箭头- 语法:
param => expression
- 接收参数并返回表达式的结果
- 如果参数个数为0或大于2,则要在
param
外加上括号,1个的话括号则为可选
1 | var greet = (name) => { |
3.4. 实参(argument) vs 形参(parameter)
- A parameter is a variable that we list as part of a function definition.
- An argument is a value that we pass to the function when we invoke it.
- 即:定义的是形参,传递的是实参
3.5. 剩余参数(Rest parameters)
1 | // JavaScript中的剩余参数是指函数定义时以...为前缀的参数,这个参数是一个没有对应形参的实参组成的一个数组,数组名就是剩余参数名 |
- 只有最后一个函数参数能作为剩余参数
3.6. 默认参数
1 | function testFunc(ninja, action = "skulking") { |
- 基本同python