你不知道的js上阅读感2-1

1. 词法阶段

  1. 词法作用域(js所采用的作用域模型)
  2. 动态作用域(Bash脚本,Perl)
  1. 编译器的工作就是词法化,词法化的过程是对源代码中的单词进行检查,如果是有状态的解析过程,还会赋给单词语义
  2. 词法作用域就是定义在词法阶段的作用域
  3. 词法的作用域主要取决在它所在的位置,一般情况下让词法作用域保持不变是比较好的选择

任何一个作用域只能被包括在一个父级作用域里面,有且唯有唯一的父级作用域

查找变量时

作用域查找会在找到第一个匹配的标识符时停止(从当前作用域一层一层向外查找,等到全局作用域还没有找到的话,就抛出参数异常错误)
无论函数在哪里被调用,无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定

遮蔽效应

在多层嵌套的作用域中定义同名标识符,内部的标识符会遮蔽外部的标识符

作用域的查找始终是从运行时所处的最内部作用域开始,逐级向外或者向上进行,直到遇到第一个匹配的标识符为止

全局变量会自动成为全局对象,可以不通过全局对象的此法名称,而是间接的通过全局对象属性的引用来对其进行访问(window.a)

2.欺骗词法

js是基于词法作用域的编程语言,但提供了两种能够在运行时改变作用域的机制,但这两种机制往往会导致性能下降

eval

function foo(str,a){
    eval(str)
    console.log(b,a)
}
var b = 2
foo('var b = 3',1)
/*得到的结果是3,1,因为eval函数会把这句话放入foo的作用域中,相当于在foo里面新建了一个变量b,
对外部的变量b产生了遮蔽作用*/

如果我们通过动态拼接字符串的方式去拼接eval里面的字符串参数,会产生很多种可能
eval能够在运行期修改书写期的词法作用域


但在严格模式下,eval()在运行时有自己的词法作用域,在其中的声明无法修改所在的作用域

function foo(str){
    "use strict"
    eval(str)
    console.log(a)
}
foo('var a = 2')
//报错为 ReferenceError a is not defined

with

with 通常被当作重复引用同i个对象中的多个属性的快捷方式,可以不需要重复引用对象本身

var obj = { a: 1 , b : 2 , c : 3 }
//普通情况下访问对象中的各个属性
obj.a = 2
obj.b = 3
obj.c = 4

//使用with快捷访问各个变量
with(obj){
    a = 3
    b = 4
    c = 5
}

但是with也会出现一些副作用,类似以下情况

function foo(obj){
    with(obj){
        a = 2
    }
}
var o1 = { a : 3 }
var o2 = { b : 3 }

foo(o1)
console.log(o1.a)  // 2

foo(o2)
console.log(o2.a)  //undefined

console.log(a)  // 2
//当执行foo函数时, o2没有a这个属性,故对其进行LHS查询时,在非严格模式下,会自动创建一个全局变量a

with可以将一个没有或者有多个属性的对象处理为一个完全隔离的词法作用域,因此对这个对象的属性也会被处理为定义在这个作用域中的词法标识符
尽管with块可以将一个对象处理为词法作用域,但是这个块内部正常的var声明并不会限制在这个块的作用域中,而是被添加到with所处函数的作用域中

eval()是如果接受了一个或多个声明的代码,就会修改其所处的词法作用域,而with声明实际上是根据你传递给它的对象凭空创建了一个全新的词法作用域

3. 性能分析

js引擎会在编译阶段进行数项的性能优化,其中有些优化依赖于能够根据代码的词法进行静态分析,并预先圈定所有变量和函数的定义位置,才能在执行过程中快速找到标识符,但如果引擎在代码中发现了eval()或者with,它只能简单的假设标识符的位置的判断都是无效的,因为无法在词法阶段明确知道eval()会接收到什么代码,这些代码回如何对作用域进行修改,也无法知道with用来创建新词法作用域的对象的内容到底是什么(也就是说有可能,所做出的优化都是无效的,从而无法进行任何优化),除此之外,存在eval或者with,运行起来一定非常慢。


  1. 写博客的理由是希望获得坚持学习的勇气,希望能一直坚持下去
  2. 能为其他小伙伴提供便利
  3. 如果文章涉及侵权或者其他,请评论或者留言指出删除此文章
  4. 文章中出现的一些见解是我自己认为重要的部分,欢迎讨论交流,互相努力
  5. 有前端的小伙伴有一起学习的愿望,可以添加qq2454459210

猜你喜欢

转载自blog.csdn.net/qq_34567015/article/details/82149335