你不知道的 JavaScript 上卷笔记
上卷很早就拜读过了,当时没有记录下来,这次也算是复习下。
1:作用域是什么 ?
作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。如果查找的目的是对变量进行赋值,那么就会使用 LHS
查询; 如果目的是获取变量的值,就会使用 RHS
查询。
LHS
和 RHS
查询都会在当前执行作用域中开始,如果当前找不到,会向上级作用域继续查找,最后到顶级作用域,无论找到或没找到都将停止。
不成功的 RHS
引用会导致抛出 ReferenceError
异常。不成功的 LHS
引用会导致自动隐式 地创建一个全局变量 (非严格模式下)
,该变量使用 LHS
引用的目标作为标识符,或者抛出 ReferenceError
异常(严格模式下)
。
2:词法作用域
词法作用域
意味着作用域是由书写代码时函数声明的位置来决定的,编译的词法分析阶段就能知道标识符在哪里以及如何声明,从而能够在执行的过程中如何对它们进行查找。
eval
和 with
都能够欺骗词法作用域:
eval
是将一个字符串代码进行演算,并且来修改以及存在的词法作用域。with
是讲一个对象的引用来当做作用域来处理,将对象的属性当做标识符来处理,从而创建一个新的词法作用域(如果对象的属性不存在,会在全局创建一个)
。
3:函数作用域和块作用域
函数
是JavaScript
中最常见的作用域单元
,但这并不是唯一的,块作用域
指的是标识符不仅可以属于函数内部,也可以属于某个代码块 {...}
。
从 ES3
开始,try/catch
结构在 catch
分句中具有块作用域。
ES6
增加了let
和 const
。
4:提升
|
|
它将var a
和a = 2
当作两个单独的声明,第一个是编译阶段
的任务,而第二个则是执行阶段
的任务。
在这个编译阶段
就把所有的声明(变量和函数)
都被移动到各自作用域
的顶端,这个过程叫做提升
。
声明本身会被提升
,而包含函数表达式的赋值在内的赋值操作不会被提升。
5:作用域闭包
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
6:this
this
实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用(也就是函数的调用方法)
。
默认绑定:foo();
隐式绑定:obj.foo();
显式绑定:foo.call(..)
,foo.apply(..)
,foo.bind(..)
new绑定:new Foo(..)
严格模式
上默认绑定的 this
会绑定到 undefined
。
显式绑定也称为硬绑定
,绑定之后无法使用隐式绑定或者显式绑定来修改 this
。
显示绑定比隐式绑定的优先级高。
new绑定比隐式绑定的优先级高。
ES6
中的箭头函数
并不会使用四条标准的绑定规则,绑定无法被修改,而是根据当前的词法作用域来决定 this
。
7:对象
getOwnPropertyDescriptor
属性描述符
writable
可写
enumerable
可枚举myObject.propertyIsEnumerable('a')
能否可枚举
configurable
可配置
|
|
|
|
|
|
|
|
in
会检查[[Prototype]]
原型链,hasOwnProperty
只会检查自身属性。
Object.keys(..)
会返回一个数组,包含所有可枚举属性,Object.getOwnPropertyNames(..)
会返回一个数组,包含所有属性,无论它们是否可枚举。
in
和 hasOwnProperty(..)
的区别在于是否查找 [[Prototype]]
链,然而,Object.keys(..)
和 Object.getOwnPropertyNames(..)
都只会查找对象直接包含的属性。
8:原型
如果要访问对象中并不存在的一个属性,[[Get]]
操作就会查找对象内部[[Prototype]]
关联的对象。这个关联关系实际上定义了一条“原型链”,在查找属性时会对它进行遍历。
所有普通对象都有内置的 Object.prototype
,指向原型链的顶端(比如说全局作用域),如 果在原型链中找不到指定的属性就会停止。toString()
、valueOf()
和其他一些通用的功能 都存在于 Object.prototype
对象上,因此语言中所有的对象都可以使用它们。
Object.create(null)
会创建一个拥有空(或者说null
) [[Prototype]]
链接的对象,这个对象无法进行委托。由于这个对象没有原型链,所以 instanceof
操作符(之前解释过)无法进行判断,因此总是会返回 false
。 这些特殊的空 [[Prototype]]
对象通常被称作“字典”
,它们完全不会受到原 型链的干扰,因此非常适合用来存储数据。
9:行为委托
行为委托认为对象之间是兄弟关系,互相委托,而不是父类和子类的关系。JavaScript
的 [[Prototype]]
机制本质上就是行为委托机制。也就是说,我们可以选择在 JavaScript
中努 力实现类机制,也可以拥抱更自然的 [[Prototype]]
委托机制。
对象关联(对象之前互相关联
)是一种编码风格,它倡导的是直接创建和关联对象,不把它们抽象成类。对象关联可以用基于 [[Prototype]]
的行为委托非常自然地实现。