深入编程
Javascript 是解释型的,实际上是动态编译程序,然后立即执行编译后的代码。
编写代码是为了给开发者阅读的,代码应该解释为什么,而非是什么。
深入 Javascript
Javascript 中”假”值的列表:
- “” (空字符串)
- 0, -0, NaN (无效数字)
- null、undefined
- false
任何不在”假”值列表中的值都是”真”值,例如[],{}等。
在Jvascript中,闭包最常见的应用是模块模式。模块模式允许你定义外部不可见的私有实现细节(变量、函数),同时也可以提供允许从外部访问的公开API。
ES6及更新版本
transpiling:通过transpiling(transformation+compiling,转换+编译)的技术,将ES6代码转化为等价(或近似)的可以在ES5环境下工作的代码。
let+for1
2
3
4
5
6
7var funcs = [];
for(let i = 0; i < 5; i++) {
funcs.push(function() {
console.log(i);
})
}
funcs[3](); // 3
for循环头部的let i 不只是为for循环本身声明了一个i,而是为循环的每一次迭代都重新声明了一个新的i。这意味着loop迭代内部创建的闭包封闭的是每次迭代中的变量。
spread/rest
ES6引入的新的运算符…,通常称为spread/rest运算符,取决于在哪/如何被使用。1
2
3
4// spread
var a = [2,3,4];
var b = [1, ...a, 5];
console.log(b); // [1,2,3,4,5]
1 | // rest |
这种用法最好的一点是,为类数组 arguments 提供了非常可靠的替代形式。
箭头函数
箭头函数总是函数表达式,并不存在箭头函数声明,箭头函数是匿名函数表达式,它们没有用于递归或者事件绑定/解绑定的命名引用。
箭头函数的主要设计目的是以特定的方式改变this的行为特性。1
2
3
4
5
6
7
8
9var controller = {
makeRequest: function() {
var self = this;
btn.addEventListner('click', function(){
//
self.makeRequest(...);
}, false)
}
}
因为 this 是动态的,通过变量 self 依赖于词法作用域的可预测性。在箭头函数内部,this 绑定不是动态的,是词法的。这是箭头函数的主要设计特性。
除了词法 this,箭头函数还有词法 arguments,它们没有自己的 arguments 数组,而是继承自父层–词法 super 和 new.target 也是一样。
代码组织
模块
- ES6 使用基于文件的模块,也就是一个文件一个模块。
- ES6 模块的 API 是静态的。也就是说,需要在模块的公开 API 中静态定义所有最高层导出,之后无法补充。
- ES6 模块是单例。
- 模块的公开 API 暴露的属性和方法并不仅仅是普通的值或引用的赋值。他们是到内部模块定义中的标识符的实际绑定(几乎类似于指针)。
- 导入模块和静态请求加载(如果还没加载的话)这个模块是一样的。
import 和 export 都必须出现在使用它们的最顶层作用域。举例来说,不能把 import 或 export 放在 if 条件中,它必须出现在所有代码块和函数的外面。
比较下面两段代码:1
2
3
4function foo() {
// ...
}
export default foo;
1 | function foo() { |
第一段代码中,导出的是此刻到函数表达式的绑定,而不是标识符foo,也就是说,export default… 接受的是一个表达式,如果之后 foo 赋了一个不同的值,模块导入得到的仍然是原来导出的函数,而不是新的值。
第二段代码,默认导出绑定实际上绑定到 foo 标识符而不是它的值,所以如果之后修改了 foo 的值,导入的值也会更新。
模块依赖环
import 语句使用外部环境(浏览器、Node.js等)提供的独立机制,来实际把模块标识符字符串解析成可用的指令,用于寻找和加载所需的模块,这个机制就是系统模块加载器。浏览器中环境提供的模块加载器会把模块标识符解析为URL,在Node.js这种服务器上就解析为本地文件系统路径。
类
// TODO