你不知道的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>的读书笔记 什么是作用域? 程序离不变量,那么变量存储在哪里?程序需要时如何找到他们? 这些问题说明需要一套设计良好的规则来存储变量, 并且之后可以 ...
随机推荐
- 检查linux的磁盘空间占用
先初步看看哪个目录占用最大$ df -h 然后细看遍历某目录的占用情况:$ sudo du -a /data | sort -nr | less(单位是KB)
- xorm中的几个坑
项目中使用的是xorm,虽然用了很顺手了,可是还是会遇到一些坑,这里纪录一些. 结构体自动忽略空字段 在xorm中,结构体会自动忽略空字段(或则说默认值,比如int 的0 ,string的" ...
- 【iCore4 双核心板_ARM】例程三十二:UART_IAP_ARM实验——更新升级STM32
实验现象及操作说明: 1.本例程共有两个代码包,APP和IAP,IAP程序功能实现将APP程序升级至STM32中. 2.直接上电或烧写程序将执行升级的APP应用程序. BIN升级文件产生方法: 1.编 ...
- Tomcat 配置详解/优化方案(转)
转载地址:https://blog.csdn.net/cicada688/article/details/14451541/ Service.xml Server.xml配置文件用于对整个容器进行相关 ...
- ubuntu 使用旧式Gnome风格的菜单
sudo apt-add-repository ppa:diesch/testing sudo apt-get update sudo apt-get install classicmenu-indi ...
- VS的ASP.NET项目中cshtml关键词出错 红线,当前上下文中不存在名称
[参考]VS的ASP.NET项目中cshtml突然出错,当前上下文中不存在名称“ViewBag” 原因:web.config 配置错误 这种情况是因为两个web.config文件版本不匹配,需要进行修 ...
- SSH配置struts校验发生No result defined for action actions.AdminLoginAction and result input
配置struts校验发生No result defined for action actions.AdminLoginAction and result input,但是登录,success.jsp, ...
- redis在php中的基本使用
//使用autoload加载相关库,这边重点就是为了require $file; spl_autoload_register(function($class) { $file = __DIR__.’/ ...
- git log --pretty=format:" "
控制显示的记录格式,常用的格式占位符写法及其代表的意义如下: 选项 说明%H 提交对象(commit)的完整哈希字串%h 提交对象的简短哈希字串%T 树对象(tree)的完整哈希字串% ...
- 【nginx】解决Nginx重启时提示nginx: [emerg] bind() to 0.0.0.0:80错误
Nginx是一款轻量级的Web服务器,特点是占有内存少,并发能力强,因而使用比较广泛,蜗牛今天在一个VPS上重启Nginx时提示“nginx: [emerg] bind() to 0.0.0.0:80 ...