什么是作用域?

作用域规定变量在什么地方可用。

函数级作用域

1.函数外声明的变量为全局变量,函数内可以直接访问全局变量:

var global_var = 10; //全局变量
function a(){
alert(global_var); //全局变量在函数内可访问
}
a(); //10

2.JavaScript变量的作用域是函数级的,只有函数可以产生新的作用域,而非块级:

function a(){ //函数
if(true){ //块
var x = 1;
}
if(false){
var y = 2;
}
alert(x); //1
alert(y); //undefined
}
a();

变量x虽然在块语句(if)中声明并赋值,但它的作用域是函数a,所以在函数a的任何位置它都可访问。

有意思的是y变量的声明和赋值虽然在false块语句里,却仍然打印出undefined而不是报错,因为JavaScript会把所有变量声明提前到函数开头,称为变量提升

function a(){
alert(x);
var x = 1;
alert(x);
}
a(); //undefined 1 //以上代码经过JavaScript变量提升后实际上是这个样子的:
function a(){
var x;
alert(x);
x = 1;
alert(x);
}

需要注意的是,在函数内声明变量一定要使用var,否则是声明了一个全局变量:

function test(){
a = 1;
}
test();
alert(a); //1

3.嵌套函数可以访问外围函数的变量

function a(){
var x = 1; function b(){
alert(x);
var y = 2; function c(){
alert(x);
alert(y);
}
c();
}
b();
}
a(); // 1 1 2

需要注意的是,嵌套函数里如果有同名变量,那么访问到的是嵌套函数里的变量

function a(){
var x = 1; function b(){
var x = 2;
alert(x);
}
b();
alert(x);
}
a(); //2 1

如何做到块级作用域

通过上面的例子我们了解到JavaScript变量作用域是函数级的,但有时候我们想用临时变量怎么办呢?

通过IIFE(立即执行函数表达式)来实现:

function a(){
if(true){
(function(){ //IIFE开始
var x = 1;
alert(x); //1
}()); //IIFE结束
//alert(x); //这儿访问不到
}
//alert(x); //这儿访问不到
}
a();

这样做的好处是不会造成变量污染,用完就没了,大家商量好,过了今晚就不再联系。

作用域链

每当JavaScript解释器进入一个函数,它都会看一下附近有哪些局部变量,把它们保存到该函数的variables对象中,并创建一个scope属性来指向外部的variables对象

1.  var x=1;
2. function a() {
3. var y = 2;
4. function b() {
5. var z = 3;
6. alert(x+y+z);
7. }
8. b();
9. }
10. a();

结合上面的代码,看看JavaScript引擎是如何处理作用域的:

  1. JavaScript把所有全局对象(变量x和函数a)放到global variables对象中

    global variables: x, a()

  2. 发现a是个函数,它需要一个scope属性来指向外部的variables(全局),同时把变量保存起来

    a.scope -> global variables

    a.variables: y, b()

  3. 来到第4行,发现b是个函数,它需要一个scope属性来指向它所在的作用域(a)

    b.scope -> a.variables

    b.variables: z

查找变量的时候,先看看variables对象有没有,没有就根据scope找上一级的variables,就这样一层一层往上找,直到找到为止。

参考资料

  1. JavaScript for PHP Developers
  2. 深入理解JavaScript
  3. You Don't Know JS

JavaScript一看就懂(1)作用域的更多相关文章

  1. JavaScript一看就懂(2)闭包

    认识闭包之前需要先了解作用域,如果你对作用域还没有足够了解,请移步JavaScript一看就懂(1)作用域 什么是闭包? 我们可以先简单认为:一个函数a定义在另一个函数b里面,这个函数a就是闭包: f ...

  2. JavaScript一看就懂(3)数组

    定义数组 var a = [1, 2, 3]; typeof a; //"object", 数组是对象 a.length; //数组长度 相关操作 a[0]; //下标访问 a.p ...

  3. 每个JavaScript工程师都应懂的33个概念

    摘要: 基础很重要啊! 原文:33 concepts every JavaScript developer should know 译文:每个 JavaScript 工程师都应懂的33个概念 作者:s ...

  4. 每个 JavaScript 工程师都应懂的33个概念

    简介 这个项目是为了帮助开发者掌握 JavaScript 概念而创立的.它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南. 本篇文章是参照 @leonardomso 创立,英文版项 ...

  5. 一看就懂的ReactJs入门教程(精华版)

    一看就懂的ReactJs入门教程(精华版) 现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和 ...

  6. 《JavaScript 闯关记》之作用域和闭包

    作用域和闭包是 JavaScript 最重要的概念之一,想要进一步学习 JavaScript,就必须理解 JavaScript 作用域和闭包的工作原理. 作用域 任何程序设计语言都有作用域的概念,简单 ...

  7. 《你必须知道的javascript(上)》- 1.作用域和闭包

    1 作用域是什么 1.1 编译原理 分词/词法分析(Tokenizing/Lexing) 将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元(token). 解析/语 ...

  8. 一看就懂的Android APP开发入门教程

    一看就懂的Android APP开发入门教程 作者: 字体:[增加 减小] 类型:转载   这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤 ...

  9. mysql取出现在的时间戳和时间时间戳转成人类看得懂的时间

    mysql取出现在的时间戳和时间时间戳转成人类看得懂的时间,我们在mysql里面他封装了一个内置的时间戳转化的函数,比如我们现在的时间戳是:1458536709 ,"%Y-%m-%d&quo ...

随机推荐

  1. 手机APP中使用history.back()返回没有效果的解决

    样式是一个超链接A标签,通过点击事件来达到返回上一页的效果. 所以通常做饭是把A标签的href写成#,然后onClick事件,刚开始我只是当成一个普通点击事件,然后使用JS进行返回. 写法如下: &l ...

  2. PHP实现WebService的简单示例和实现步骤

    首先我创建的文件有: api.php api的接口类文件 api.wsdl 我创建产生的最后要调用的接口文件 cometrue.php 注册service api类内容的所有内容的执行文件 creat ...

  3. CentOS7上安装FTP服务

    ---------------------------------------------------------------------------------------------------- ...

  4. 来了解一下Mysql索引的相关知识:基础概念、性能影响、索引类型、创建原则、注意事项

    索引的基础概念索引类似于书籍的目录,要想找到一本书的某个特定主题,需要先查找书的目录,定位对应的页码:存储引擎使用类似的方式进行数据查询,先去索引当中找到对应的值,然后根据匹配的索引找到对应的数据行 ...

  5. 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题

    layout: post title: 2018-03-03-解决win下凭据删除不干净而无法登录共项目录的问题 key: 20180303 tags: GIT 版本管理 modify_date: 2 ...

  6. java并发 - 自底向上的原理分析

    [TOC] 事先声明,我只是java并发的新手,这篇文章也只是我阅读<java并发编程的艺术>一书(内容主要涉及前3章)的一些总结和感悟.希望大家能多多讨论,对于错误的地方还请指出. 0. ...

  7. Redis Cluster的搭建与部署,实现redis的分布式方案

    前言 上篇Redis Sentinel安装与部署,实现redis的高可用实现了redis的高可用,针对的主要是master宕机的情况,我们发现所有节点的数据都是一样的,那么一旦数据量过大,redi也会 ...

  8. js 滚动到一定位置导航定位在页面最顶部

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 2_Add Two Numbers --LeetCode

    原题如下: 思路:在一个while中遍历两个链表,直到最长的链表为空,或者没有进位.每一步获取两个链表对应的结点的值a,b,然后相加a+b.如果上一步又进位,那就加a+b+1,若由于进位加1后还产生进 ...

  10. R+先知︱Facebook大规模时序预测『真』神器——Prophet(遍地代码图)

    经统专业看到预测的packages都是很眼馋的.除了之前的forecast包,现在这个prophet功能也很强大.本packages是由机器之心报道之后,抽空在周末试玩几小时.一些基本介绍可见机器之心 ...