你不知道的JavaScript-2.词法作用域
考虑以下代码:
function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar( b * 3 );
}
foo( 2 ); // 2, 4, 12
在这个例子中有三个逐级嵌套的作用域。
- 包含着整个全局作用域,其中只有一个标识符: foo 。
- 包含着 foo 所创建的作用域,其中有三个标识符: a 、 bar 和 b 。
- 包含着 bar 所创建的作用域,其中只有一个标识符: c 。
全局变量会自动成为全局对象(比如浏览器中的 window 对象)的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。
window.a
通过方式可以访问那些被同名局部变量所遮蔽的全局变量。但非全局的变量如果被遮蔽了,无论如何都无法被访问到。
eval
JavaScript 中的 eval(..) 函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。换句话说,可以在你写的代码中用程序生成代码并运行,就好像代码是写在那个位置的一样。
考虑以下代码:
function foo(str, a) {
eval( str ); // 欺骗!
console.log( a, b );
}
var b = 2;
foo( "var b = 3;", 1 ); // 1, 3
eval(..) 调用中的 "var b = 3;" 这段代码会被当作本来就在那里一样来处理。
由于那段代码声明了一个新的变量 b ,因此它对已经存在的 foo(..) 的词法作用域进行了修改。事实上,和前面提到的原理一样,这段代码实际上在 foo(..) 内部创建了一个变量 b ,并遮蔽了外部(全局)作用域中的同名变量。
with
with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
// 单调乏味的重复 "obj"
obj.a = 2;
obj.b = 3;
obj.c = 4;
// 简单的快捷方式
with (obj) {
a = 3;
b = 4;
c = 5;
}
但实际上这不仅仅是为了方便地访问对象属性。考虑如下代码:
function foo(obj) {
with (obj) {
a = 2;
}
}
var o1 = {
a: 3
};
var o2 = {
b: 3
};
foo( o1 );
console.log( o1.a ); //
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!
可以注意到一个奇怪的副作用,实际上 a = 2 赋值操作创建了一个全局的变量 a 。这是怎么回事?
可以这样理解,当我们传递 o1 给 with 时, with 所声明的作用域是 o1 ,而这个作用域中含有一个同 o1.a 属性相符的标识符。但当我们将 o2 作为作用域时,其中并没有 a 标识符,因此进行了正常的 LHS 标识符查找.
o2 的作用域、 foo(..) 的作用域和全局作用域中都没有找到标识符 a ,因此当 a=2 执行时,自动创建了一个全局变量(因为是非严格模式)。
eval、with 会导致引擎无法在编译时对作用域查找进行优化,从而影响性能。
你不知道的JavaScript-2.词法作用域的更多相关文章
- 关于JavaScript的词法作用域及变量提升的个人理解
关于JavaScript的作用域,最近听到一个名词:“词法作用域”:以前没有听说过(读书少),记录一下对此的理解,加深印象. 词法作用域:在JavaScript中,一个函数的作用域,在这个函数定义好的 ...
- JavaScript的词法作用域问题
多年以前,当我怀揣着前端工程师的梦想时,曾经认真阅读过<JavaScript高级程序设计(第2版)>.里面有一个问题(P147),让我一直百思不得其解. function createFu ...
- JavaScript 使用词法作用域,没有动态作用域
function foo() { console.log( a ); } function bar() { var a = 3; foo(); } var a = 2; bar(); 上面的代码,控制 ...
- 读书笔记-你不知道的JS上-词法作用域
JS引擎 编译与执行 Javascript引擎会在词法分析和代码生成阶段对运行性能进行优化,包含对冗余元素进行优化(例如对语句在不影响结果的情况下进行重新组合). 对于Javascript来说,大部分 ...
- javascript 欺骗词法作用域
如果词法作用域完全由写代码期间函数所声明的位置来定义,怎样才能在运行时来"修改"(也可以说欺骗)词法作用域呢? JavaScript 中有两种机制来实现这个目的.社区普遍认为 ...
- 你不知道的JavaScript——this词法
https://www.cnblogs.com/hutaoer/p/3423782.htmlhttps://www.cnblogs.com/vicky-li/p/8669549.htmlhttps:/ ...
- javascript的词法作用域
这个概念是js中相当基础也是极为重要的,很多想当然的错误或感觉怪异的问题都是和这个东西有关.所以,本文主要说下这个名词的概念以及讨论下他牵扯出来的有关变量.函数.闭包的问题. 由变量开始谈 习惯性先来 ...
- 对于javascript的词法作用域的思考
曾经看到过这样一段有意思的程序: var a=3; function scopeTest(){ console.log(a); var a=2; console.log(a); } scopeTest ...
- 你不知道的JS之作用域和闭包(二)词法作用域
原文:你不知道的js系列 词法作用域(Lexical Scope) Lex time 一个标准的编译器的第一个阶段就是分词(token化) 词法作用域就是在词法分析时定义的作用域.换句话说,词法作用域 ...
- 你不知道的JavaScript --- 作用域相关
本篇是<你不知道的JavaScript>的读书笔记 什么是作用域? 程序离不变量,那么变量存储在哪里?程序需要时如何找到他们? 这些问题说明需要一套设计良好的规则来存储变量, 并且之后可以 ...
随机推荐
- XSS测试代码
无script的Xss <img/src=# onerror=alert('XSS')> HTML5 XSS测试代码 <video> <source onerror=” ...
- git学习小游戏
学习git可以试试这个游戏:https://learngitbranching.js.org/
- mysql 批量导入 Packets larger than max_allowed_packet are not allowed
解决方法 :http://blog.csdn.net/gtosky4u/article/details/8581281
- .net IIS MVC Rest api 跨域 PUT DELETE 404 无法使用问题解决方案
一.WebConfig配置法(system.webServer 重点是 httpProtocol handlers) http://www.jinxuliang.com/blog/article/re ...
- Linux系统解析域名的先后顺序【转帖】
Linux系统解析域名的先后顺序 gd_WWW已经在本地(/etc/hosts)进行指向,但是竟然还能解析到外网,让我百思不得其解.经过不断查找发现域名解析与以下四个文件有关: /etc/hosts ...
- 某公司面试java试题之【二】,看看吧,说不定就是你将要做的题
这次做的题是在是太多了,五页呢,吓死宝宝了!
- python sort和sorted区别。
前者是方法,后者是函数.oop和opp区别的经典体现.好好领会,就能知道什么时候写类什么时候写函数好.
- 【Python】博客信息爬取-微信消息自动发送
1.环境安装 python -m pip install --upgrade pip pip install bs4 pip install wxpy pip install lxml 2.博客爬取及 ...
- Excel数据与DateTable数据的转换
public class ExcelHelper : IDisposable { private string fileName = null; //文件名 private IWorkbook wor ...
- PCB画板总结
最近几天完成了第一个PCB电路板.虽然器件不是很多,手动布线了4次才达到自己理想的效果. 但是还是有很多细节只有亲自拿到了自己做的板子,亲自焊接之后,才知道自己哪里不合适. 这是修改了4次之后的最终的 ...