js作用域与作用域链

一直对Js的作用域有点迷糊,今天偶然读到JavaScript权威指南,立马被吸引住了,写的真不错。我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫。

一:函数作用域

先看一小段代码:

[javascript] view plain copy

  1. var scope="global";
  2. function t(){
  3. console.log(scope);
  4. var scope="local"
  5. console.log(scope);
  6. }
  7. t();

(PS: console.log()是firebug提供的调试工具,很好用,有兴趣的童鞋可以用下,比浏览器+alert好用多了)

第一句输出的是: "undefined",而不是 "global"

第二讲输出的是:"local"

你可能会认为第一句会输出:"global",因为代码还没执行var scope="local",所以肯定会输出“global"。

我说这想法完全没错,只不过用错了对象。我们首先要区分Javascript的函数作用域与我们熟知的C/C++等的块级作用域。

在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的。而Javascript压根没有块级作用域,而是函数作用域.

所谓函数作用域就是说:-》变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

所以根据函数作用域的意思,可以将上述代码重写如下:

[javascript] view plain copy

  1. var scope="global";
  2. function t(){
  3. var scope;
  4. console.log(scope);
  5. scope="local"
  6. console.log(scope);
  7. }
  8. t();

我们可以看到,由于函数作用域的特性,局部变量在整个函数体始终是由定义的,我们可以将变量声明”提前“到函数体顶部,同时变量初始化还在原来位置。

为什么说Js没有块级作用域呢,有以下代码为证:

[javascript] view plain copy

  1. var name="global";
  2. if(true){
  3. var name="local";
  4. console.log(name)
  5. }
  6. console.log(name);

都输出是“local",如果有块级作用域,明显if语句将创建局部变量name,并不会修改全局name,可是没有这样,所以Js没有块级作用域。

现在很好理解为什么会得出那样的结果了。scope声明覆盖了全局的scope,但是还没有赋值,所以输出:”undefined“。

所以下面的代码也就很好理解了。

[javascript] view plain copy

  1. function t(flag){
  2. if(flag){
  3. var s="ifscope";
  4. for(var i=0;i<2;i++)
  5. ;
  6. }
  7. console.log(i);
  8. console.log(s);
  9. }
  10. t(true);

输出:2  ”ifscope"

二:变量作用域

还是首先看一段代码:

[javascript] view plain copy

  1. function t(flag){
  2. if(flag){
  3. s="ifscope";
  4. for(var i=0;i<2;i++)
  5. ;
  6. }
  7. console.log(i);
  8. }
  9. t(true);
  10. console.log(s);

就是上面的翻版,知识将声明s中的var去掉。

程序会报错还是输出“ifscope"呢?

让我揭开谜底吧,会输出:”ifscope"

这主要是Js中没有用var声明的变量都是全局变量,而且是顶层对象的属性。

所以你用console.log(window.s)也是会输出“ifconfig"

当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除

var name=1    ->不可删除

sex=”girl“         ->可删除

this.age=22    ->可删除

三:作用域链

先来看一段代码:

[javascript] view plain copy

  1. name="lwy";
  2. function t(){
  3. var name="tlwy";
  4. function s(){
  5. var name="slwy";
  6. console.log(name);
  7. }
  8. function ss(){
  9. console.log(name);
  10. }
  11. s();
  12. ss();
  13. }
  14. t();

当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。然后从链表开头寻找变量name,很明显

name是"slwy"。

但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy"

下面看一个很容易犯错的例子:

[html] view plain copy

  1. <html>
  2. <head>
  3. <script type="text/javascript">
  4. function buttonInit(){
  5. for(var i=1;i<4;i++){
  6. var b=document.getElementById("button"+i);
  7. b.addEventListener("click",function(){ alert("Button"+i);},false);
  8. }
  9. }
  10. window.onload=buttonInit;
  11. </script>
  12. </head>
  13. <body>
  14. <button id="button1">Button1</button>
  15. <button id="button2">Button2</button>
  16. <button id="button3">Button3</button>
  17. </body>
  18. </html>

当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?

很容易犯错,对是的,三个按钮都是弹出:"Button4",你答对了吗?

当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,

所以弹出”button4“。

四:with语句

说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。

看下面代码

[javascript] view plain copy

  1. person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};
  2. with(person.wife){
  3. console.log(name);
  4. }

with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".

with语句结束后,作用域链恢复正常。

时间: 2024-11-12 16:08:39

js作用域与作用域链的相关文章

js的变量,变量作用域,作用域链

变量声明: 使用var关键字声明,如果使用没有声明的变量,则JS会自动声明此变量根据变量作用域.如果变量只声明为赋值,则此时值是undefined.重复声明变量,在JS不会报错,会依据最后一次的声明来处理变量. 变量作用域: 一个变量的作用域是,程序代码定义这个变量的区域,全局变量在程序代码内任何地方都可以访问. 包括在{}函数,对象内的变量(属性)成为局部变量. 在函数体内定义的变量成为局部变量,作用域也是局部,函数参数也是局部变量. 他们只在函数体内有意义. 在函数体内,局部变量优先于全局变

第十八篇 js高级知识---作用域链

一直有想法去写写js方面的东西,我个人是最喜欢js这门语言,喜欢的他的自由和强大,虽然作为脚本语言有很多限制的地方,但也不失为一个好的语言,尤其是在H5出现之后.下面开始说说js的方面的东西,由于自己的能力有现,有点地方说的不明白,还请高手指点.这个文章,如果有时间的话应该会写一个系列,包括js的高级方面的知识,最终希望能够说到js的引擎方面的东西.千里之行,始于足下,下面开始说说最简单的一个东西—js的作用域链,时常也比较容易弄错,也算是自己做一个纪录. 首先看一段代码: function t

js中的作用域链

js中的执行环境: 所谓执行环境(有时也称环境)它是JavaScript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据 ,决定了它们各自的行为.而每个执行环境都有一个与之相关的变量对象,环境中定义的所有变量和函数都保存在这个对象中. js中的作用域链: 每个函数都有自己的执行环境,当代码在执行环境中执行时,就会创建变量对象的作用域链.作用域链保证了对执行环境有权访问所有变量和函数的有序访问.作用域链的前端,始终都是当前执行的代码所在的环境的变量对象,如果环境是一个函数,那么它的

Js 作用域与作用域链与执行上下文不得不说的故事 ?(? ???ω??? ?)?

最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js只有函数作用域(function-based),没有块级作用域,也就是只有函数会有自己的作用域,其他都没有. 接着,作用域分为全局作用域与局部作用域. 全局作用域中的对象可以在代码的任何地方访问,一般来说,下面情况的对象会在全局作用域中: 最外层函数和在最外层函数外面定义的变量 没有通过关键字"va

js闭包和作用域链

闭包 闭包 函数对象之间可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内 这种特性称做“闭包”. 什么是变量? 变量就是为一切事物赋的一个name; var的作用,初始化变量. 变量作用域 程序源码中定义这个变量的区域就就是变量作用域.(名字放在什么地方了) 全局变量拥有全局作用域,在js代码的任何地方都是有定义的.(这个名字很响亮) 在函数体内声明的变量在函数体内有效,他们是局部变量,函数参数也是局部变量他们只在函数体内有定义.(里层的能拿到的外层的值,外层的拿不到里层的

js的作用域与作用域链

JavaScript的作用域和作用域链.在初学JavaScript时,觉得它就和其他语言没啥区别,尤其是作用域这块,想当然的以为"全局变量就是在整个程序的任何地方都可以访问,也就是写在函数外的变量,局部变量也就是写在函数内部或循环体内部,出了循环体和函数就不可访问",但是在JavaScript中并不是这么简单,需要去深入的学习. 一. 什么是作用域任何程序语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围.比如C/C++等,都是块级作用域,也就是说在每一个代码块内声明的变

了解 JS 作用域与作用域链

(1)作用域 一个变量的作用域(scope)是程序源代码中定义的这个变量的区域. 1. 在JS中使用的是词法作用域(lexical scope) 不在任何函数内声明的变量(函数内省略var的也算全局)称作全局变量(global scope) 在函数内声明的变量具有函数作用域(function scope),属于局部变量 局部变量优先级高于全局变量 var name="one"; function test(){ var name="two"; console.log

JS详细图解作用域链与闭包

JS详细图解作用域链与闭包 攻克闭包难题 初学JavaScript的时候,我在学习闭包上,走了很多弯路.而这次重新回过头来对基础知识进行梳理,要讲清楚闭包,也是一个非常大的挑战. 闭包有多重要?如果你是初入前端的朋友,我没有办法直观的告诉你闭包在实际开发中的无处不在,但是我可以告诉你,前端面试,必问闭包.面试官们常常用对闭包的了解程度来判定面试者的基础水平,保守估计,10个前端面试者,至少5个都死在闭包上. 可是为什么,闭包如此重要,还是有那么多人没有搞清楚呢?是因为大家不愿意学习吗?还真不是,

理解js中的作用域,作用域链以及闭包

作用域变量作用域的类型:全局变量和局部变量全局作用域对于最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的 <script> var outerVar = "outer"; function fn(){ console.log(outerVar); } fn();//result:outer </script> 局部作用域和全局用域相反,局部作用域一般只在固定的代码片段内可访问到,对于函数外部是无法访问的 <script> fu

JS高级(三)--原型链、闭包、作用域、函数的四种调用方式

一.原型链(家族族谱) 概念:JS里面的对象可能会有父对象,父对象还会有父对象,.....祖先 根本:继承 属性:对象中几乎都会有一个__proto__属性,指向他的父对象 意义:可以实现让该对象访问到父对象中相关属性 根对象:Object.prototype var arr=[1,3,5] arr.__proto__:Array.prototype arr.__proto__.__proto__就是找到了根对象 function Animal(){} var cat=new Animal();