X

曜彤.手记

随记,关于互联网技术、产品与创业

吉 ICP 备10004938-2号

《你不知道的 JavaScript》读书笔记(上)


旧书清理系列。

第 1 部分 - 作用域和闭包

  1. (Page:7)变量的赋值操作会执行两个动作:
  1. (Page:12)严格模式下禁止自动或隐式创建全局变量。在 RHS 查询(引用变量的值)下,若在作用域链中找不到变量,则会抛出 ReferenceError 异常。而在 LHS 查询(变量出现在赋值操作左侧)下,若在作用域链中找不到变量,非严格模式下引擎会自动在顶层作用域创建一个全局变量,严格模式下同样抛出 ReferenceError 异常。
  2. (Page:14)作用域:

- 词法作用域

- 动态作用域

  1. (Page:17)两种词法欺骗方式

- eval

function foo(str, a) {
  eval(str);  // 对已有词法进行了修改;
  console.log(a, b);
}
var b = 2;
foo("var b = 3;", 1);  // 1 3.

- with

function foo(obj) {
  with (obj) { y = 2; }
}
var o = { x: 3 };  // 对 y 的无效引用会导致在顶层全局作用域内自动创建该变量;
foo(o);
console.log(window.y);  // 2.
  1. (Page:24)最小特权原则:在软件设计中,应该最小限度地暴露必要的内容,而将其他内容都“隐藏”起来。
  2. (Page:27)利用 IIFE 实现函数作用域
var x = 2;
;(function foo() {  // 具名函数表达式;
  var x = 3;
  console.log(x);  // 3.
})();
console.log(x);  // 2.
  1. (Page:30)块作用域
  1. (Page:38)包括变量和函数在内的所有声明都会在任何代码被执行前首先被处理(提升),即“先有声明,后有赋值”。赋值给变量的函数表达式并不会被提升,且函数会首先被提升,然后才是变量
foo();  // 1.
var foo;  // 被忽略;
function foo() {
  console.log(1);
}
foo = function() {
  console.log(2);
}
  1. (Page:44)闭包:当函数可以记住并访问所在词法作用域时,就产生了闭包,即使函数时在当前词法作用域之外执行。
function foo() {
  var x = 2;
  function bar() {
    console.log(x);
  }
  return bar;
}
var baz = foo();
baz();  // 2.
for (var i = 1; i <= 5; ++i) {
  (function(j) {  // 相当于 “var j = i”;
    setTimeout(function timer() {
      console.log(j);
    }, j * 1000);
  })(i);
}

  1. (Page:54)简单的模块机制:
// 单例模式;
var MyModules = (function Manager() {
  var modules = {};
  function define(name, deps, impl) {
    for (var i = 0; i < deps.length; ++i) {
      deps[i] = modules[deps[i]];
    }
    modules[name] = impl.apply(impl, deps);  // 存储模块定义;
  }
  function get(name) {
    return modules[name];
  }
  return {
    define: define,
    get: get,
  }
})();
  1. (Page:65)箭头函数中的词法 this
var obj = {
  count: 0,
  cool: function coolFn() {
    if (this.count < 1) {
      setTimeout(() => {
        this.count++;  // 箭头函数直接使用词法作用域中的 this,而非运行时调用者的 this;
        console.log('awesome!');
      }, 100);
    }
  }
};
obj.cool();

第 2 部分 - this 和对象原型

  1. (Page:79)在任何情况下,this 都不指向函数的词法作用域
  2. (Page:84)当被调用函数体处于严格模式下时,其内部的 this 无法绑定到全局对象
  3. (Page:90)new 操作符的具体流程:
function Person(name) {
  this.name = name;
}
// new Person('YHSPY');
var person = {};
person.__proto__ = Person.prototype;
Person.call(person, 'YHSPY');
  1. (Page:99)箭头函数的 this 会由外层作用域来决定(词法作用域),当外层函数被绑定到固定的 this 后,内存箭头函数在调用时的 this 便无法再被更改。
  2. (Page:101)判断 this 的绑定对象:
  1. (Page:106)在对象中,属性名永远都是字符串。当使用 string 类型之外的其他值作为属性名时,该值会被引擎自动转换为一个字符串,包括数字。
  2. (Page:109)当为数组添加字符串数字值时,该值会被转化为一个数字索引:
var arr = [];
arr['1'] = 1;
console.log(arr);  // (2) [empty, 1].
  1. (Page:114)对象(浅)不变性:

- 对象常量属性:不可修改、重定义或删除。

var myObject = {};
Object.defineProperty(myObject, 'key', {
  value: 4,
  writable: false,
  configurable: false,
});

- 禁止扩展:禁止添加新属性且保留已有属性。

var myObject = { existingKey: 2 };
Object.preventExtensions(myObject);

- 密封:不能添加新属性,也不能重新配置或删除现有属性(可以修改值)。

var myObject = { existingKey: 2 };
Object.seal(myObject);

- 冻结:不能添加新属性,不能重新配置或删除现有属性,也无法修改属性值。

var myObject = { existingKey: 2 };
Object.freeze(myObject);
  1. (Page:118)访问描述符 getter 与 setter:
var myObject = {
  get v() {
    return this.__v__;
  },
  set v(val) {
    this.__v__ = val;
  }
};
myObject.v = 1;
console.log(myObject.v);
  1. (Page:121)infor..in 均会查找对象的原型链。
  2. (Page:145)对象“属性屏蔽”的复杂性:如果 foo 不直接存在于 myObject 中而是存在于原型链上层时 myObject.foo = "bar" 会出现的三种情况:


这是文章底线,下面是评论
  暂无评论,欢迎勾搭 :)