<js>你不知道的js笔记
词法作用域
- 无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。词法作用域意味着作用域是由书写代码时函数声明的位置来决定。
1 | let c = 2 |
- 在严格模式的程序中,eval(..)在运行时有其自己的词法作用域,意味着其中的声明无法修改所在的作用域。
1 | function c(str) { |
- setTimeout(..)和setInterval(..)的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的函数代码。
- with 使用注意
1 | function f1(obj) { |
作用域
- 函数作用域的含义是指,属于这个函数的全部变量都可以在整个函数的范围内使用及复用(事实上在嵌套的作用域中也可以使用)。
- 区分函数声明和表达式最简单的方法是function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。
- 提升是指声明会被视为存在于其所出现的作用域的整个范围内。但是使let进行的声明不会在块作用域中进行提升。
作用域提升
- 只有声明本身会被提升,而赋值或其他运行逻辑会留在原地。如果提升改变了代码执行的顺序,会造成非常严重的破坏。
1 | console.log(a)//undefined |
- 函数声明会被提升,但是函数表达式却不会被提升。
1 | f1()//1 |
- 即使是具名的函数表达式,名称标识符在赋值之前也无法在所在作用域中。
1 | f1()//TypeError |
- 函数优先提升,一个值得注意的细节(这个细节可以出现在有多个“重复”声明的代码中)是函数会首先被提升,然后才是变量。
1 | a()//1 |
- 尽管重复var声明会被忽略掉,但出现在后面的函数声明还是可以覆盖前面的。
1 | a()//2 |
- 一个普通块内部的函数声明通常会被提升到所在作用域的顶部,这个过程不会像下的代码暗示的那样可以被条件判断所控制。但是需要注意这个行为并不可靠,JavaScript未来的版本中有可能发生改变,因此应该尽可能避免在块内部声明函数。
1 | a()//TypeError: a is not a function,**这个demo和书里面的就不一样了书里面说会log 2** |
闭包
- 当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
- 模块有两个主要特征:(1)为创建内部作用域而调用了一个包装函数;(2)包装函数的返回值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭包。
this
- 学this的第一步是明this既不指向函数自身也不指向函数的词法作用域,
- this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
调用位置
- 调用位置就是函数在代码中被调用的位置(而不是声明的位置)。
this绑定规则
默认规则
- 独立函数调用,,函数调用时应用this的默认绑定,因this指向全局对象。
- 严格模式下this为undefined
隐式绑定
1 | function a() { |
- 隐式丢失
1 | function a() { |
显示绑定
- JavaScript提供的绝大多数函数以及你自己创建的所有函数都可以使call(..)apply(..)bind(…)方法。
new绑定使
- new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执[[原]]连接。
- 这个新对象会绑定到函数调用this。
- 如果函数没有返回其他对象,那new表达式中的函数调用会自动返回这个新对象。
优先级
- new > 显示 > 隐式 > 默认
被忽略的this
- 如果你null或undefined作this的绑定对象传call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
1 | function a() { |
更安全的this
1 | function a() { |
软绑定
1 | if (!Function.prototype.softBind) { |
箭头函数
- 箭头函数不使this的四种标准规则,而是根据外层(函数或者全局)作用域来决this。
1 | function a() { |