书籍 在线阅读

第一章 块级绑定

块级声明

块级声明:块级声明指的是该声明的变量无法被代码块外部访问,块作用域又被称为此法作用域

创建条件

  • 函数内部
  • 在代码块 (即{ }内部)

let 声明

禁止重复声明

就是不可以对声明的标识符进行覆盖,会报错。

  1. var count = 30; => let count = 30 也不会报错
  2. // 不会抛出错误
  3. if (condition) {
  4. let count = 40;
  5. // 其它代码
  6. }
  7. 因为 let声明的变量在if中,并非与var声明的处于同一级

const 声明

该种声明的变量被视为常量,意味着他们不能被再次赋值,所以const 声明都必须在声明处初始化

  • const 变量的值如果是个对象,那么这个对象本身可以被修改

  • 都是块级声明,都不会进行变量提示

  • 不可以对已存在的标识符重新定义(赋值)
let const
声明时 可以不赋值 必须赋值

将对象赋给const 变量

const声明只是阻止变量和值的再次绑定而不是值本身的修改。

  1. const person ={
  2. name:"xioaming"
  3. }
  4. //正确
  5. person.name = "chu"
  6. //错误
  7. person = {
  8. name:"chu"
  9. }
  10. const 阻止的是绑定的修改而不是绑定值的修改

暂存性死区

let 或 const 声明的变量在声明之前不能被访问

循环中的块级绑定

例子:不想让循环外部访问到内部的索引计数器

  1. for(var i=0;i<10;i++){
  2. console.log("over")
  3. }
  4. //这里仍然可以访问到i
  5. console.log(i) //10
  6. for(let i=0;i<10;i++){
  7. console.log("over")
  8. }
  9. //这里会报错
  10. console.log(i)

循环中的函数

因为每次迭代的过程中i是被共享的,意味着循环中创建的函数都保持这对相同变量的引用,当循环结束后i的值为10

  1. var funcs = [];
  2. for (var i = 0; i < 10; i++) {
  3. funcs.push(function() { console.log(i); });
  4. }
  5. funcs.forEach(function(func) {
  6. func(); // 输出 "10" 共10次
  7. });

解决方法:循环内部使用即时调用函数表达式,来迫使每一次迭代时创建一份当前索引值的拷贝

  1. for(var i=0;i<10;i++){
  2. funcs.push((function(value){
  3. return function(){
  4. console.log(value)
  5. }
  6. }(i)))
  7. }

循环中的let声明

在每次迭代中,一个新的同名变量会被创建并初始化

  1. var funcs = [];
  2. for (let i = 0; i < 10; i++) {
  3. funcs.push(function() {
  4. console.log(i);
  5. });
  6. }
  7. funcs.forEach(function(func) {
  8. func(); // 输出 0,1,2 ... 9
  9. })

for-in与 for-of 。每次循环的开始都会创建一个新的变量key的绑定,所以每个函数都会有各自key变量值的备份。

  1. var funcs = [],
  2. object = {
  3. a: true,
  4. b: true,
  5. c: true
  6. };
  7. for (let key in object) {
  8. funcs.push(function() {
  9. console.log(key);
  10. });
  11. }
  12. funcs.forEach(function(func) {
  13. func(); // 输出 "a","b" 和 "c"
  14. });

全局块级绑定

当在全局作用域内使用var声明时会创建一个全局变量,同时也是全局对象(浏览器环境下是window)的一个属性。
意味着全局对象的属性可能会被重写覆盖

  1. // 在浏览器中运行
  2. var RegExp = "Hello!";
  3. console.log(window.RegExp); // "Hello!"

如果你在全局作用域中使用let或者const,那么绑定就会发生在全局作用域内,但是不会向全局对象内部添加任何属性,意味着不能使用 let 或 const 重写全局变量,仅能屏蔽他们。

  1. // 在浏览器中运行
  2. let RegExp = "Hello!";
  3. console.log(RegExp); // "Hello!"
  4. console.log(window.RegExp === RegExp); // false

总结

目前关于块级绑定的最佳实践是使用 const 作为默认的声明方式,当变量需要更改时切换为 let 声明。保证代码中最基本的不可变性能防止错误的发生。

第二章 字符串与正则表达式

更佳的Unicode支持

第三章 函数

带默认参数的函数

ES5默认参数模拟

原理:都是可选参数因为未传入实参给他们的情况下会使用各自的默认值
缺点:如果给timeout 传入的值为 0 ,那么timeout 的值会被替换为2000,因为0被默认为假值

  1. function makeRequest(url, timeout, callback) {
  2. timeout = timeout || 2000;
  3. callback = callback || function() {};
  4. // 其它部分
  5. }
  6. => 更加健壮的写法
  7. function makeRequest(url, timeout, callback) {
  8. timeout = (typeof timeout !== "undefined") ? timeout : 2000;
  9. callback = (typeof callback !== "undefined") ? callback : function() {};
  10. // 其它部分
  11. }

ES6默认参数

  1. function makeRequest(url, timeout = 2000, callback = function() {}) {
  2. // 其余代码
  3. }
  1. 可以指定任意一个函数参数的默认值
  2. function makeRequest(url, timeout = 2000, callback) {
  3. // 其余代码
  4. }
  5. // 使用 timeout 的默认值
  6. makeRequest("/foo", undefined, function(body) {
  7. doSomething(body);
  8. });
  9. // 使用 timeout 的默认值
  10. makeRequest("/foo");
  11. // 不使用 timeout 的默认值
  12. makeRequest("/foo", null, function(body) {
  13. doSomething(body);
  14. });
  15. 注意:在提供参数值的时候,null是有效的

默认参数对arguments对象的影响

  1. function mixArgs(first, second) {
  2. console.log(first === arguments[0]);
  3. console.log(second === arguments[1]);
  4. first = "c";
  5. second = "d";
  6. console.log(first === arguments[0]);
  7. console.log(second === arguments[1]);
  8. }
  9. mixArgs("a", "b");
  10. true
  11. true
  12. true
  13. true
  14. 当时不理解,但是调试代码之后会发现 first 就是参数 a(也就是arguments[0])

arguments 对象在非严格模式下总是实行更新反映出命名参数的变化,因此当first和second变量获得新值之后,arguments[0] 和 arguments[1] 也同步更新,使得 === 比较的值为 true 。
ES5的严格模式下,上述不成立。

当使用ES6默认参数时,表现和ES5严格模式一致。

  1. // 非严格模式
  2. function mixArgs(first, second = "b") {
  3. console.log(arguments.length);
  4. console.log(first === arguments[0]);
  5. console.log(second === arguments[1]);
  6. first = "c";
  7. second = "d"
  8. console.log(first === arguments[0]);
  9. console.log(second === arguments[1]);
  10. }
  11. mixArgs("a");
  12. 1
  13. true
  14. false
  15. false
  16. false