轻松5句话解决JavaScript的作用域

javascript 程序的每一个字节都是在这个或那个运行上下文(execution context)中执行的。你可以把这些上下文想象为代码的邻居,它们可以给每一行代码指明:从何处来,朋友和邻居又是谁。没错,这是很重要的信息,因为 javascript社会有相当严格的规则,规定谁可以跟谁交往。运行上下文则是有大门把守的社区而非其内开放的小门。

我们通常可以把这些社会边界称为作用域,并且有充足的重要性在每一位邻居的宪章里立法,而这个宪章就是我们要说的上下文的作用域链(scope chain)。在特定的邻里关系内,代码只能访问它的作用域链内的变量。与超出它邻里的变量比起来,代码更喜欢跟本地(local,即局部)的打交道。

任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,轻松搞定JavaScript作用域

一、“JavaScript中无块级作用域”

在Java或C#中存在块级作用域,即:大括号也是一个作用域。

public static void main ()
{ if(1==1){
 String name = "seven";
 }
 System.out.println(name);
}// 报错
public static void Main()
{ if(1==1){
 string name = "seven";
 }
 Console.WriteLine(name);
}// 报错

在JavaScript语言中无块级作用域

function Main(){
 if(1==1){
 var name = 'seven';
 }
 console.log(name);
}// 输出: seven

二、JavaScript采用函数作用域

在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。

function Main(){
 var innerValue = 'seven';
}

Main();

console.log(innerValue);

// 报错:Uncaught ReferenceError: innerValue is not defined

三、JavaScript的作用域链

由于JavaScript中的每个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域链。

xo = 'alex';

function Func(){
 var xo = "seven";
 function inner(){
 var xo = 'alvin';
 console.log(xo);
 }
 inner();
}
Func();

如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。

四、JavaScript的作用域链执行前已创建

JavaScript的作用域在被执行之前已经创建,日后再去执行时只需要按照作用域链去寻找即可。

示例一:

xo = 'alex';

function Func(){
 var xo = "seven";
 function inner(){

 console.log(xo);
 }
 return inner;
}

var ret = Func();
ret();
// 输出结果: seven

上述代码,在函数被调用之前作用域链已经存在:

全局作用域 -> Func函数作用域 -> inner函数作用域
当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

示例二:

xo = 'alex';

function Func(){
 var xo = "eirc";
 function inner(){

 console.log(xo);
 }
 xo = 'seven';
 return inner;
}

var ret = Func();
ret();
// 输出结果: seven

上述代码和示例一的目的相同,也是强调在函数被调用之前作用域链已经存在:

全局作用域 -> Func函数作用域 -> inner函数作用域
不同的时,在执行【var ret = Func();】时,Func作用域中的xo变量的值已经由 “eric” 被重置为 “seven”,所以之后再执行【ret();】时,就只能找到“seven”。

示例三:

xo = 'alex';
function Bar(){
 console.log(xo);
}

function Func(){
 var xo = "seven";

 return Bar;
}

var ret = Func();
ret();
// 输出结果: alex

上述代码,在函数被执行之前已经创建了两条作用域链:

全局作用域 -> Bar函数作用域
全局作用域 -> Func函数作用域
当执行【ret();】时,ret代指的Bar函数,而Bar函数的作用域链已经存在:全局作用域 -> Bar函数作用域,所以,执行时会根据已经存在的作用域链去寻找。

五、声明提前

在JavaScript中如果不创建变量,直接去使用,则报错:

console.log(xxoo);
// 报错:Uncaught ReferenceError: xxoo is not defined

JavaScript中如果创建值而不赋值,则该值为 undefined,如:

var xxoo;
console.log(xxoo);
// 输出:undefined
在函数内如果这么写:
function Foo(){
 console.log(xo);
 var xo = 'seven';
}

Foo();
// 输出:undefined

上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。

Js是一门很有趣的语言,由于它的很多特性是针对HTML中DOM的操作,因而显得随意而略失严谨,但随着前端的不断繁荣发展和Node的兴起,Js已经不再是"toy language"或是jQuery时代的"CSS扩展",本文提到的这些无论是对新手还是从传统Web开发中过度过来的Js开发人员来说,都很容易被混淆或误解,希望本文可以有所帮助。

(0)

相关推荐

  • js函数内变量的作用域分析

    本文实例分析了js函数内变量的作用域.分享给大家供大家参考.具体分析如下: 先看一个函数实例: 复制代码 代码如下: <html> <head> </head> <body> <script type="text/javascript"> var a = 5; var c = 3; function t(){  var a = 6;  var b = 10;  document.write(a+'-----'+b);  doc

  • 只需五句话搞定JavaScript作用域(经典)

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一."JavaScript中无块级作用域" 在Java或C#中存在块级作用域,即:大括号也是一个作用域. public static void main () { if(1==1){ String name = "seven"; } System.out.println(name); }// 报错 public static v

  • 谈一谈js中的执行环境及作用域

    最近在面试时被问到了对作用域链的理解,感觉当时回答的不是很好,今天就来说说js中的作用域链吧. 首先来说说js中的执行环境,所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据 ,决定了它们各自的行为.而每个执行环境都有一个与之相关的变量对象,环境中定义的所有变量和函数都保存在这个对象中. 理解了执行环境,现在就看看什么是作用域链吧.每个函数都有自己的执行环境,当代码在执行环境中执行时,就会创建变量对象的作用域链.作用域链保证了对执

  • 浅析JavaScript作用域链、执行上下文与闭包

    闭包和作用域链是JavaScript中比较重要的概念,这两天翻阅了一些资料,把相关知识点给大家总结了以下. JavaScript 采用词法作用域(lexical scoping),函数执行依赖的变量作用域是由函数定义的时候决定,而不是函数执行的时候决定.以下面的代码片段举例说明,通常来说(基于栈的实现,如 C 语言) foo 被调用之后函数内的本地变量 scope 会被释放,但是从词法上看 foo 的内嵌匿名函数中 scope 应该指的是 foo 的本地变量 scope ,并且实际上代码的运行结

  • 深入浅析javascript中的作用域(推荐)

    所谓的作用域,可以简单理解为一个可以读.写的范围(区域),有些js经验的同学可能会说:"js没有块级作用域",js除了全局作用域外,只有函数可以创建作用域.作用域的一个好处就是可以隔离变量. 我们通过一些例子来帮助我们理解js中的作用域. alert(a); var a = 1; 如果对作用域一点不了解的同学可能会说 alert的是1或者报错:但实际上是undefined: 说到这里,我们首先说一下js逐行解析代码之前做的一些准备工作, js在逐行读代码之前,会做一些"预解析

  • JavaScript变量的作用域全解析

    变量作用域是程序中定义这个变量的区域. 先来看一段示例: /*  代码1  */ var scope = "global "; function checkScope() { var scope = "local "; function childCheck() { var scope = "childLocal "; document.write(scope); } function childUndefined() { document.wr

  • 聊一聊JavaScript作用域和作用域链

    每种编程语言,其变量都有一定的有效范围,超过这个范围之后,变量就失效了,这就是变量的作用域.从数学的角度来看,就是自变量的域. 作用域是变量的可访问范围,即作用域控制着变量与函数的可见性和生命周期.在 JavaScript 中, 对象和函数同样也是变量,变量在声明他们的函数体以及这个函数体嵌套的任意函数体内部都是有定义的. 一.静态作用域和动态作用域 静态作用域 是指声明的作用域是根据程序正文在编译时就确定的,也称为词法作用域.大多数现代程序设计语言都是采用静态作用域规则,JavaScript就

  • JavaScript 作用域链解析

    JavaScript中有Scope(作用域),Scope chain(作用域链),Execute context(执行上下文),Active Object (活动对象),Dynamic Scope(动态作用域),Closure(闭包)这些概念,要理解这些概念,我们从静态和动态两个方面去分析一下. 首先我们写一个简单的function来做一个例子: 复制代码 代码如下: function add(num1, num2){ var sum = num1 + num2; return sum; } 我

  • 深入理解javascript作用域第二篇之词法作用域和动态作用域

    前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作模型导致的,作用域分为词法作用域和动态作用域,分清这两种作用域模型就能够对变量查找过程有清晰的认识.本文是深入理解javascript作用域系列第二篇--词法作用域和动态作用域 词法作用域 第一篇介绍过,编译器的第一个工作阶段叫作分词,就是把由字符组成的字符串分解成词法单元.这个概念是理解词法作用域

  • 轻松5句话解决JavaScript的作用域

    javascript 程序的每一个字节都是在这个或那个运行上下文(execution context)中执行的.你可以把这些上下文想象为代码的邻居,它们可以给每一行代码指明:从何处来,朋友和邻居又是谁.没错,这是很重要的信息,因为 javascript社会有相当严格的规则,规定谁可以跟谁交往.运行上下文则是有大门把守的社区而非其内开放的小门. 我们通常可以把这些社会边界称为作用域,并且有充足的重要性在每一位邻居的宪章里立法,而这个宪章就是我们要说的上下文的作用域链(scope chain).在特

  • 教会你完全搞定MySQL数据库 轻松八句话

    一.连接MYSQL 格式: mysql -h主机地址 -u用户名 -p用户密码 1.例1:连接到本机上的MySQL: 首先在打开DOS窗口,然后进入目录 mysqlbin,再键入命令mysql -uroot -p,回车后提示你输密码,如果刚安装好MYSQL,超级用户root是没有密码的,故直接回车即可进入到MYSQL中了,MYSQL的提示符是:mysql>. 2.例2:连接到远程主机上的MYSQL.假设远程主机的IP为:110.110.110.110,用户名为root,密码为abcd123.则键

  • 五句话帮你轻松搞定js原型链

    原型链是一种机制,指的是JavaScript每个对象包括原型对象都有一个内置的[[proto]]属性指向创建它的函数对象的原型对象,即prototype属性. 作用:原型链的存在,主要是为了实现对象的继承. 一. 记住以下5句话,轻松搞定js原型链 Function 和 Object 都是构造函数 所有的构造函数都是Function new出来的(Function自己new了自己):所有的原型对象都是Object new出来的(Object new了自己的原型对象) 每一个构造函数都有一个pro

  • 理解JavaScript变量作用域更轻松

    JavaScript本身作为一门简单的语言,就其变量作用域问题一样令不少人头晕,这主要是因为JavaScript闭包的存在.本文不打算深入讲解JavaScript变量作用域问题(其实本人也没有能力能把这一话题讲的深入些),也不讲"闭包"话题,本文只讨论最实用的JavaScript作用域知识点. 一.JavaScript作用域分类 JavaScript就两种作用域:全局(window).函数级(function).函数级(function)不要理解为"块级(大括号{}级)&qu

  • 轻松解决JavaScript定时器越走越快的问题

    解决JavaScript定时器越走越快的问题 之前在项目中写了定时器来做循环播放,但是总是会有越走越快的问题,开始是以为前后的HTML代码拼接的有问题,时间紧急的情况下反复改了很多也没什么效果,后来发现是js定时器的问题,在这里记录一下. (setinterval)多次初始化 使用js定时器(setinterval)首要的问题就是要记得清除,即调用(clearInterval)方法,由于没有使用定时器的经验,我一开始是没有清除定时器,程序每一次初始化的时候都调用一次定时器,之前的定时器实例没有被

  • 全面了解JavaScript的作用域链

    JavaScript的作用域链 这是一个非常重要的知识点了,了解了JavaScript的作用域链的话,能帮助我们理解很多'异常'问题. 下面我们来看一个小例子,前面我说过的声明提前的例子. var name = 'Skylor.min'; function echo() { alert(name); var name = 'mm'; alert(name); alert(age); } echo(); 对于这个例子,没有接触过这方面的时候,第一反应是会纠结下,这第一个的name,到底调用全局变量

  • JavaScript变量作用域_动力节点Java学院整理

    在JavaScript中,用var申明的变量实际上是有作用域的. 如果一个变量在函数体内部申明,则该变量的作用域为整个函数体,在函数体外不可引用该变量: 'use strict'; function foo() { var x = 1; x = x + 1; } x = x + 2; // ReferenceError! 无法在函数体外引用变量x 如果两个不同的函数各自申明了同一个变量,那么该变量只在各自的函数体内起作用.换句话说,不同函数内部的同名变量互相独立,互不影响: 'use stric

  • 解决javascript:window.close()在chrome,Firefox下失效的问题

    window.close(),一看就知道是用来关闭浏览器窗口的方法.W3CSchool对该方法的解释如下:方法 close() 将关闭有 window 指定的顶层浏览器窗口.某个窗口可以通过调用 self.close() 或只调用 close() 来关闭其自身.只有通过 JavaScript 代码打开的窗口才能够由 JavaScript 代码关闭.这阻止了恶意的脚本终止用户的浏览器. 在IE中,window.close()能生效,在生效的时候,会弹出提示框,询问你是否关闭该窗口,如图: 点击"是

  • JavaScript中作用域链的概念及用途讲解

    从零开始讲解JavaScript中作用域链的概念及用途 引言 之前我写过一篇关于JavaScript中的对象的一篇文章,里面也提到了作用域链的概念,相信大家对这个概念还是没有很深的理解,并且这个概念也是面试中经常问到的,因为这个概念实在太重要了,在我们平时写代码时,也可能会因为作用域链的问题,而出现莫名其妙的bug,导致我们花费大量的时间都查找不出原因.所以我就准备单独写一篇关于作用域链的文章,来帮大家更好地理解这个概念. 正文 一.执行环境 首先,我们要引入一个概念,叫做执行环境(下面简称环境

随机推荐