<你不知道的JavaScript-上卷> 2018-02-27

此类文章全是笔记,用于帮助自己快速回忆起书籍所讲述的内容,对他人参考意义较少


第一部分、作用域和闭包

当定义了一个函数后,当前的作用域就会被保存下来,并且成为函数内部状态的一部分

JavaScript是动态的编译语言,大部分情况下编译发生在代码执行前的几微妙(甚至更短)的时间内,JavaScript引擎优化-JIT,延迟编译等优化

当变量出现在赋值操作的左侧时LHS查询-赋值操作的目标是谁 ,非左侧时RHS-谁是赋值操作的源头

ReferenceError同作用域判别失败,TypeError代表作用域判别成功,但是对结果的操作是非法或不合理的


欺骗词法 eval和with


ES3 try/catch的catch分局会创建一个块作用域

块级作用域可以避免闭包的内存泄漏


每个作用域都会提升,变量声明和函数声明会提升,但是函数表达式不会提升

具名的函数表达式也不会提升,且函数名会在函数内部定义为函数自身

var  foo = function bar () {} 

相当于

var foo

foo = function () { var bar = ...self...}

函数首先会被提升,然后才是变量

我们习惯将var a = 1看作一个声明,实际上是两个单独的声明,第一个是编译阶段的任务,第二个是执行阶段的任务


当函数可以记住并访问所在的词法作用域时,就产生了闭包

只要使用了回调函数,实际上就是在使用闭包


动态作用域只关心它们从何处调用,也就是说,作用域链是基于调用栈的,而不是代码中的作用域嵌套,和this很像

JavaScript中的作用域是词法作用域,而非动态作用域,词法作用域的最重要特征是它的定义过程发生在代码的书写阶段(如果没有使用eval和with)


ES6中的箭头函数引入了this词法的行为,放弃所有普通this绑定的规则,取而代之的是用当前的词法作用域覆盖了this本来的值

第二部分、this和对象原型

this是在运行时进行绑定的,而不是在编写时绑定,她的上下文取决于函数调用时的各种条件。this的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式


默认绑定,非严格模式this绑定在全局对象上,严格模式下绑定到undefined

隐式绑定,调用位置有上下文时,对象属性引用链只有最后一层在调用位置起作用,函数参数传递也是隐式赋值

显式绑定,call()和apply()方法,ES5提供bind()函数,硬绑定


new绑定

1.创建一个全新的对象

2.这个新对象会被执行[[Prototype]]连接

3.这个新对象会绑定到函数调用的this

4.如果没有返回其它对象,那么new表达式中的函数调用会自动返回这个新对象


如果把null或者undefined作为this的绑定对象传入call‘apply或者bind,这些值会被忽略,实际应用的是默认绑定规则


判断一个运行中的函数的this绑定的,需要找到这个函数的直接调用位置

1.由new调用,绑定到新创建的对象

2.由call或者apply(或者bind)调用,绑定到制定的对象

3.由上下文对象调用,绑定到上下文对象

4.默认,严格模式绑定到undefined,非严格模式绑定到全局对象


对象可以通过两种形式定义:声明形式和构造形式

var obj = {key: value}; //声明

var obj = new Object(); obj.key = value //构造


在对象中,属性名永远是字符串,即使是数字也不例外

从ES5开始,所有的属性都具备了属性描述符

如果引用了当前词法作用域中不纯在的变量,不会像对象属性一样返回undefeated,而是抛出一个ReferencrError异常


所有prototype最终都会指向内置的Object.prototype


Object.create的polyfill代码

Object.create = function (o) {

    function F(){}

    F.prototype = o

    return new F()

}


ES6的class只是prototype的语法糖,并不会在声明时静态复制所有行为


匿名函数没有name标识符,有三个缺点

1.调试栈更难追踪

2.自我引用(递归、事件(解除)绑定,等等)更难

3.代码(稍微)更难理解

简洁方法没有第一和第三个缺点


你可能感兴趣的:(<你不知道的JavaScript-上卷> 2018-02-27)