JavaScript作用域那些事
作用域
(1)、作用域也叫执行环境(execution context)是JavaScript中一个重要的概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。在JavaScript中变量的作用域有全局作用域和局部作用域,全局变量是指变量没有在函数体内声明或者在函数内声明的时候没有带var,即表示拥有全局作用域,相反变量在函数内声明带var称为局部变量,拥有局部作用域。特殊的虽然函数参数不带var但它也属于局部变量。
var a = 1; //全局变量
function fn1( b ){ //局部变量
var c = 2; //局部变量
d = 3; //全局变量
}
(2)、接下来介绍一下解析过程。浏览器有专门的一段程序用于解析JavaScript,暂且给他取个名字叫JavaScript解析工具,这个解析过程至少有两个过程(当然不仅仅有两个,像编译原理的词法分析什么的,这里不提):1.寻找目标(预解析)。包括var、function、参数等。 2.逐行解读代码。接下来通过实例来具体分析是怎么做的:
alert( a ); //undefined
var a = 1;
function fn (){
alert( 2 );
}
具体过程:
alert( b ); //function a() { alert( 4 ) };
var b = 1;
alert( b ); //
function b () {
alert( 2 );
}
alert( b ); //
var b = 3;
alert( b ); //
function b (){
alert( 4 );
}
alert( b ); //
if( true ){
var a = 1;
}
alert( a ); //
在一个 if 语句中定义变量 a。如果是在 C、C++等语言中,a会在 if 语句执行完毕后被销毁。但在JavaScript中,if 语句中的变量声明会将变量添加到当前的作用域(在这里是全局作用域)中。特别是在使用 for 语句时:
for( var i=0; i<10; i++ ){
doSothing(i);
}
alert(i); //
对于块级作用域的语言来说,for语句初始化变量的表达式所定义的变量,只会存在于循环的环境中。而对于JavaScript来说,有for语句创建的变量 i 即使在for循环执行结束后,也依旧会存在于循环外部的作用域中。
(4)、函数是作用域,有预解析等过程,if for语句不是作用域。尽量不要在 if for中定义变量和函数调用,否则有浏览器问题:
alert(fn1); //chrome,FF 弹出 undefine. ie 弹出整段函数(function fn19=(){alert( 123 )})
if( true ){
var a = 1;
function fn1(){
alert( 123 )
}
}
var a = 1;
function change{
var b = 2;
function swap(){
var c = b;
b = a;
a = c; //这里可以访问a,b,c
} //这里可以访问a和b,但不能访问c
swap();
} //这里只能访问a
change();
通过上面例子我们知道作用域之间的 联系是线性、有次序的。每个作用域可以沿着作用域链向上搜索,但任何作用域不能通过向下搜索而进入另一个作用域中,搜索时先搜索自己作用域内是否存在该变量,若不存在则再一级一级往上搜索。
2.既然我们不能通过这种方式去访问局部作用域,那我们也可以用以下方法去获取函数内部的值:
(1)、通过设置全局变量获取
var str = '';
function fn1(){
var a = '需要拿到的值';
str = a;
}
fn1();
alert( str ); //弹出'需要拿到的值'
(2)、通过函数调用获取
function fn2(){
var a = '需要拿到的值';
fn3( a );
}
fn2();
function fn3( a ){
alert( a );
}
作用域链的改变
JavaScript里的 with语句和 catch语句可以在作用域的头部临时增加一个变量对象,该变量对象会在代码执行后被移除,具体来说就是当执行到这两个语句时,作用域链会得到加长。
(1)、with语句的作用是避免重复书写代码,如:
function fn(){
with(document){
var btn = getElementById('btn');
var input = getElementsByClassName('input');
}
}
这里with语句接收一个document对象,因此它的变量对象中就包含了document对象的所有属性和方法,但这个变量对象就被添加到作用域的最前头,这样看似避免了重复书写,但是性能并不好。因为被推到作用域前头,其他的变量就处于第二个作用域当中了,若要逐级访问,访问代价比较大。可以用一局部变量代替document,即可解决,而不必用with语句。
(2)catch语句与with相类似:
try {
//可能出错的代码
} catch (error) {
//出错时怎么处理
}
当出现错误执行catch语句,将出错对象放入作用域头部,然后catch中其他的变量就处于第二个作用域当中了。
最后通过几个例子强化一下,每个例子都是在前一个例子的基础上做一些调整,但结果却不一样。
(1)、
var a = 1;
function fn1(){
alert(a); //undefined
var a = 2;
}
fn1();
alert(a); //
(2)、将(1)的第四行改为 a = 2。
var a = 1;
function fn1(){
alert(a); //
a = 2;
}
fn1();
alert(a); //
(3)、将(2)中的 fn1函数添加参数 a,虽然结果与(1)相同,但解析过程不同。
var a = 1;
function fn1( a ){ //a相当于局部变量,相当于var a
alert(a); //undefined
a = 2;
}
fn1();
alert(a); //
(4)、在(3)的基础上给第6行添加参数 a。
var a = 1;
function fn1( a ){ //a相当于局部变量,相当于var a
alert(a); //
a = 2;
}
fn1(a);
alert(a); //
有错误的地方请指正。
参考资料:《JavaScript高级程序设计》
JavaScript作用域那些事的更多相关文章
- [译] 你该知道的javascript作用域 (javascript scope)(转)
javascript有一些对于初学者甚至是有经验的开发者都难以理解的概念. 这个部分是针对那些听到 : 作用域, 闭包, this, 命名空间, 函数作用域, 函数作用域, 全局作用域, 变量作用域( ...
- JavaScript作用域闭包简述
JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...
- JavaScript 作用域和变量提升
本文是这篇文章的简单翻译. 如果按照下面的代码按照JavaScript程序的执行方式执行,alert函数会显示什么? var foo = 1; function bar() { if (!foo) { ...
- 深入理解JavaScript作用域和作用域链
前言 JavaScript 中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! ...
- 理解 JavaScript 作用域(转)
简介 JavaScript 有个特性称为作用域.尽管对于很多开发新手来说,作用域的概念不容易理解,我会尽可能地从最简单的角度向你解释它们.理解作用域能让你编写更优雅.错误更少的代码,并能帮助你实现强大 ...
- JavaScript作用域
JavaScript作用域 JavaScript作用域一直是前端开发的难题,现在只要用五句话就可解决. 一.“JavaScript中无块级作用域” 在Java或C#中存在块级作用域,即:大括号也是一个 ...
- 关于Javascript作用域及作用域链的总结
本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...
- JavaScript作用域链
之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...
- Python自动化 【第十六篇】:JavaScript作用域和Dom收尾
本节内容: javascript作用域 DOM收尾 JavaScript作用域 JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走 ...
随机推荐
- Spring源码学习:第2步--使用SLF4j+Log4j日志框架替换掉其自身的commons-logging日志框架
正如Spring官方文档所述,其底层的实现选择了commons-logging作为日志框架.这一"失足"性的选择,竟连Spring自身都抱怨.但是,谁叫Spring如此优秀呢,即使 ...
- 浅析JavaScript的prototype
一.JavaScript对象的创建 (1)对象方法 function Student(name){ this.name=name; this.showName=function(){ alert(&q ...
- 误删 /user/bin目录后的补救
当危险的动作发生, 误删 /user/bin目录后的补救 以下是昨天晚上真实的误操作现场,模拟记录一下 (这是测试环境,所以操作得很随意,有些执行动作很不规范) 在上面编译一个软件Dboop,完事以后 ...
- 2.java.util.logging.Logger使用详解
一.java.util.logging.Logger简介 java.util.logging.Logger不是什么新鲜东西了,1.4就有了,可是因为log4j的存在,这个logger一直沉默着, 其实 ...
- npm scripts 使用指南
转载自:http://www.ruanyifeng.com/blog/2016/10/npm_scripts.html Node 开发离不开 npm,而脚本功能是 npm 最强大.最常用的功能之一. ...
- centos7环境下mysql5.7的安装与配置
最近无事闲来折腾虚拟机,以前都是折腾云服务器,现在自己捣捣.看到mysql的教程蛮好的,准备做个笔记.原文来自mysql5.7的安装与配置(centos7环境) 第一步:下载mysql [root@M ...
- 使用listview空控件展示数据
1.使用listview控件可以一次性的将有关的全部图像保存在控件中,建立集合图像. 图像列表控件的主要属性 属性 ...
- 使用属性升级MyBank
一.访问修饰符 private :使用private访问修饰符修饰的属性或者方法只能在本类中使用 public :可以在任何类中访问到 二.this 关键字:代表当前类,this.属性:代 ...
- C#,一份超简单的数据库帮助类,SqlHelp
简单,实用,留存. using System; using System.Collections.Generic; using System.Configuration; using System.D ...
- Jmeter-基于Ubuntu运行
这几天折腾了很久,整合了一套接口自动化的持续集成工具,先从最基础的运行Jmeter说起.由于我是用Docker部署的持续集成环境,所以接口运行必须在服务器上 一:在Linux服务器先安装jdk 1:先 ...