作用域

  (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 );
}

  具体过程:

    1.寻找目标。包括var、function、参数等
      a = undefined       (所有的变量在正式运行代码之前,都会提前赋值一个值,即undefined)。
      fn = function() { alert(2) }    (所有函数在正式运行之前,都是整个函数块)
    2.逐行解读代码。
      解读代码时表达式会改变预解析中的值,如以上代码解读到第二行时,a = undefined 变为了 a = 1;
 
特殊的:如果预解析过程中遇到重名的,只留一个。如变量和函数重名了,就只留函数。再来一个例子说明:
 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 ); //
解析过程还是那两步,只是多了重名的情况。1.预解析后只留下  b = function b(){ alert(4) }。2.逐行解读后,预解析中a的值变为3,若在代码的最后调用 b(), 则会在控制台报错。
 
  (3)JavaScript中没有块级作用域。先看一个例子:
 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 )
}
}
作用域链
  1.当代码在一个环境中执行时,会创建变量对象的一个作用域链。它的作用是保证对执行环境有权访问所有变量和函数的有序访问。也就是说作用域链就像是一种绳索可以将各个作用域连接起来,已达到可以访问各个域中的变量,当然这种访问是要遵守一定的规则的,即局部作用域可以通过作用域链访问所有的全局作用域,但是全局作用域不能访问局部环境中的任何变量或函数。看下面的例子:
 
 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作用域那些事的更多相关文章

  1. [译] 你该知道的javascript作用域 (javascript scope)(转)

    javascript有一些对于初学者甚至是有经验的开发者都难以理解的概念. 这个部分是针对那些听到 : 作用域, 闭包, this, 命名空间, 函数作用域, 函数作用域, 全局作用域, 变量作用域( ...

  2. JavaScript作用域闭包简述

    JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...

  3. JavaScript 作用域和变量提升

    本文是这篇文章的简单翻译. 如果按照下面的代码按照JavaScript程序的执行方式执行,alert函数会显示什么? var foo = 1; function bar() { if (!foo) { ...

  4. 深入理解JavaScript作用域和作用域链

    前言 JavaScript 中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! ...

  5. 理解 JavaScript 作用域(转)

    简介 JavaScript 有个特性称为作用域.尽管对于很多开发新手来说,作用域的概念不容易理解,我会尽可能地从最简单的角度向你解释它们.理解作用域能让你编写更优雅.错误更少的代码,并能帮助你实现强大 ...

  6. JavaScript作用域

    JavaScript作用域 JavaScript作用域一直是前端开发的难题,现在只要用五句话就可解决. 一.“JavaScript中无块级作用域” 在Java或C#中存在块级作用域,即:大括号也是一个 ...

  7. 关于Javascript作用域及作用域链的总结

    本文是根据以下文章以及<Javascript高级程序设计(第三版)>第四章相关内容总结的. 1.Javascript作用域原理,地址:http://www.laruence.com/200 ...

  8. JavaScript作用域链

    之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...

  9. Python自动化 【第十六篇】:JavaScript作用域和Dom收尾

    本节内容: javascript作用域 DOM收尾 JavaScript作用域 JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走 ...

随机推荐

  1. centos6上yum安装drbd(内核:2.6.32.696)

    author:headsen  chen date: 2017-11-20  15:11:21 notice: 个人原创,转载请注明,否则依法追究法律责任 前期准备: 两台机器:配置主机名分别为: l ...

  2. 部署wcf出现的问题与解决方法

    我将本机作为服务器开发时,没出什么问题,将wcf服务端寄缩到另一台电脑上时,出现了一些问题,这里总结下: 1.wcf服务器和另一个网站应用出问题 服务器的iis上有一个网站应用,当我将wcf服务寄缩到 ...

  3. redis分片和哨兵

    1 Redis的使用 1.1 Redis入门案例 1.1.1 什么样的数据使用缓存 说明:使用缓存其实为了减少用户查询数据库的时间.如果数据频繁的变更.不适用缓存.缓存中的数据应该保存修改频率不高的数 ...

  4. 兄弟连教育分享:用CSS实现鼠标悬停提示的方法

    兄弟连教育分享:用CSS实现鼠标悬停提示的方法 本文,兄弟连HTML5培训,分享了纯CSS实现鼠标悬停提示的方法.给大家供大家参考.具体分析如下: 这是一款比较漂亮的鼠标悬停提示效果,用纯CSS代码实 ...

  5. numpy用法小结

    前言 个人感觉网上对numpy的总结感觉不够详尽细致,在这里我对numpy做个相对细致的小结吧,在数据分析与人工智能方面会有所涉及到的东西在这里都说说吧,也是对自己学习的一种小结! numpy用法的介 ...

  6. HTTP 0.9 HTTP 1.0 HTTP 1.1 HTTP 2.0区别

    HTTP协议 :Hyper Text Transfer Protocol(超文本传输协议),是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议.是互联网上应用 ...

  7. java 10 中 var关键字用法

    引用:https://mp.weixin.qq.com/s/n1tcJ0CywSi0j-YycGPwxg what java10引入了局部变量折断 var用于声明局部变量. 如var user=new ...

  8. Day3---------网络基础和DOS命令

    一.网络分类 1.地理位置 1).局域网(LAN) 2).城域网(MAN) 3).广域网(WAN) 2.传输介质 1).有线网 2).光纤网 3).无线网 3.层--------设备 传输层----- ...

  9. Webpack的加载器

    一.什么是加载器(loaders)loaders 用于转换应用程序的资源文件,他们是运行在nodejs下的函数 使用参数来获取一个资源的来源并且返回一个新的来源(资源的位置),例如:你可以使用load ...

  10. 0x00-Kali Linux 系列入门篇

    Kali Linux介绍篇 Kali Linux 官网:https://www.kali.org/ Kali Linux 前身是著名渗透测试系统BackTrack ,是一个基于 Debian 的 Li ...