今天是2018年12月23号,新的一年马上就要到来了,,,
前情回顾
作为在前端界一直努力的小学生,越来越发觉JavaScript的深邃和高冷。她总是热切地向我招手,让我靠她更近一些,当我马上可以触及她的时候,她又把我甩开好远,这种只可远观的角度让我又爱又恨,好像锤她一顿,可是却又补舍得,撇撇嘴告诉自己,老子就不信还追不上你...
这一追,又到了2019年了...

为何突然想到要写小结
作为前端界的小白,很多东西都是靠自己去摸索,技术平台就是长居客,看着牛人分享的技术,刚开始还能记住,假以时日没有在项目中运用到就会淡忘,最后还是发现,自己理解的东西要通过自己的语言保存下来,虽然深度达不到牛人的层次,但是自己用足矣,如果可以帮到其他人,也算是功德一件啊!
另一个原因就是可以提高一下自己的表达能力,每次和产品的沟通,说多了就是泪啊...

废话不多说,开干
1. eval和with
首先,在这本书的第一章节中讲述了词法作用域(在这里不做讲解),并且提到了通过这两个方法可以改变已经变异的词法作用域,下面首先对着两个函数进行解析。
1.1 eval
首先看下面的栗子:
eval("console.log("Hello Word!")");
输出的结果: Hello Word!
eval("(function(){
console.log("Hello Word!")
})()");
这两个简单的栗子,可以比较直观的看到,eval函数的参数虽然是字符串,但是依然会把这个字符串执行,这个就是eval函数的一个执行结果:它可以接受一个字符串作为参数,并且会行使编译器的职责,把这段字符串作为正常的书写代码进行编译。
1.2 with
with的通常用法是:重复引用一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
举个栗子:
var obj ={
a : 1,
b : 2,
c : 3
};
改变obj中属性一般写法:
obj.a = 4,
obj.b = 5,
obj.c = 6,
with的写法:
with(obj){
a = 4,
b = 5,
c = 6,
}
另一个栗子:
非严格模式下
function foo (obj){
with(obj){
a = 2;
}
}
var o1 = {
a : 3
};
var o2 = {
b : 3
}
var a = 5;
foo(o1);
console.log(o1.a);//2
foo(o2);
console.log(o2.a);//undefined
console.log(a)//2
为什么打印出来2 ???
首先o1中的a输出2是比较好理解的,因为a本身就是o1的一个属性,只是在函数foo中改变了o1中的属性值,重新赋值为2; 那么为什么o2中的值没有改变?为什么打印a为2呢??
这里就得说一下with这个函数的特点:
1.with可以将一个对象处理为完全隔离的词法作用域,所以这个对象中的属性也会被定义为这个对象(也就是这个词法作用域)中的词法标识符。
通过对象o1和o2在被函数foo处理之后,打印出来的o1.a和o2.b就可以看到,o2中没有这个属性,经过函数foo中的with函数处理之后,并没有引用全局变量a,也没有给o2创建这个属性,所以o2.a的值是undefined;
2.with虽然可以将一个对象处理为词法作用域,但是这个块内部正常声明的变量并不会限制在这个块的作用域中,而是被添加到with所处的函数作用域中
通过上面的栗子来说,o2这个对象中没有属性a,在foo函数中的with函数处理时,通过a = 2;这条语句在全局下创建了一个属相a,并且赋值为2(非严格模式下),
关于改变词法作用域
在论坛中关于这两个方法改变作用域的说法众说纷纭,这篇文档不做对比,只说一说这两个方法在性能上的观点。
此文建议在项目中应该少用或者不用。
原因:这两个方法的特点就是在运行的过程中会修改或者创建新的作用域,以此达到欺骗在书写代码时已经创建好的词法作用域。
简单介绍一下javascript引擎的编译过程:javascript引擎在编译阶段就会对代码进行优化,把编译好的变量或者函数预先确定下来,并在后面的执行过程中可以直接调用,不需要重新去编译。
但是当编译器遇到eval和with这两个函数时,因为这两个函数会改变或者重新创建作用域,所以编译器不会提前编译变量或者函数,也就不会作相应的代码优化,在后续的代码加载运行过程就会延长,也就是使用这两个函数中的哪一个都会造成代码的运行变慢。

谨慎使用。 谨慎使用。 谨慎使用。
文章多出引用了《你不知道的javascript》中的文字,读者可以查看这本书籍了解更多详细的细节,感谢正本书的作者,因为他们的劳动,让我更热爱了这门语言,感谢!!!