一直对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语句结束后,作用域链恢复正常。

Js作用域与作用域链详解[转]的更多相关文章

  1. JS作用域,作用域,作用链详解

    前言   通过本文,你大概明白作用域,作用域链是什么,毕竟这也算JS中的基本概念. 一.作用域(scope) 什么是作用域,你可以理解为你所声明变量的可用范围,我在某个范围内申明了一个变量,且这个变量 ...

  2. 你不知道的JavaScript--Item15 prototype原型和原型链详解

    用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了, ...

  3. JS中的event 对象详解

    JS中的event 对象详解   JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...

  4. js中鼠标滚轮事件详解

    js中鼠标滚轮事件详解   (以下内容部分内容参考了http://adomas.org/javascript-mouse-wheel/ ) 之前js 仿Photoshop鼠标滚轮控制输入框取值中已使用 ...

  5. ext.js的mvc开发模式详解

    ext.js的mvc开发模式详解和环境配置 在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开 ...

  6. 微信JS接口汇总及使用详解

    这篇文章主要介绍了微信JS接口汇总及使用详解,十分的全面.详尽,包含分享到朋友圈,分享给朋友,分享到QQ,拍照或从手机相册中选图,识别音频并返回识别结果,使用微信内置地图查看位置等接口,有需要的小伙伴 ...

  7. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  8. js中中括号,大括号使用详解

    js中中括号,大括号使用详解 一.总结 一句话总结:{ } 是一个对象,[ ] 是一个数组 1.js大括号{}表示什么意思? 对象 { } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或 ...

  9. js对象浅拷贝和深拷贝详解

    js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...

  10. amazeui中的js插件有哪些(详解功能)

    amazeui中的js插件有哪些(详解功能) 一.总结 一句话总结: 二.amazeui中的js插件有哪些 1.UI 增强 警告框Alert 按钮交互Button 折叠面板Collapse 下拉组件D ...

随机推荐

  1. 用PHP实现守护进程任务后台运行与多线程(php-resque使用说明)

    消息队列处理后台任务带来的问题 项目中经常会有后台运行任务的需求,比如发送邮件时,因为要连接邮件服务器,往往需要5-10秒甚至更长时间,如果能先给用户一个成功的提示信息,然后在后台慢慢处理发送邮件的操 ...

  2. Git入门详解

    查看分支:git branch 创建分支:git branch <name> 切换分支:git checkout <name> 创建+切换分支:git checkout -b ...

  3. oracle split

    select * from table(fun_strsplit('1,2,3,4,5')); 1.创建一个类型 ) 2.创建函数 CREATE OR REPLACE FUNCTION Fun_Str ...

  4. SqlServer 事务和异常处理示例

    BEGIN TRANSACTION--开始事务 DECLARE @errorSun INT --定义错误计数器SET @errorSun=0 --没错为0 UPDATE dbo.Test SET te ...

  5. IIS报错 未将对象引用设置到对象的实例。

    在vs中运行正常的项目 ,发布到IIS总是提示 未将对象引用设置到对象的实例. 运行静态页面 html正常,只是打开.aspx页面的时候报错,在确保了数据库,配置,权限均正常的情况下. 错误原因:先安 ...

  6. ios英语口语800句应用源码

    前几天突发奇想做了个很水的应用,名字叫chinese 800(汉语口语800句),现在让别人传上去了(正在传). 今天又改了一下变成了英语口语800句.加了广告条 ui 没有优化,我随便整的两个图片, ...

  7. 【风马一族_php】PHP与Mysql建立连接

    让php发出 Hi作为基础 http://www.cnblogs.com/sows/p/5990157.html 配置apache      ../apache/conf/httpd.conf 创建p ...

  8. 2_JavaScript日期格式化

          第二章 JavaScript 时间格式化 2.1 Ticks 转换为常规日期 2.2 常规日期格式化 <input type="button" value=&qu ...

  9. IOS基础——实例变量四种范围类型

    1.为了强制一个对象隐藏其数据,编译器限制实例变量范围以限制其在程序中的可见性. 但是为了提供灵活性,苹果也让开发者显示设置范围(四选一). 2.四种编译指令如下: @private 实例变量只能被声 ...

  10. Custom PeopleSoft Queries

      The following SQL identifies custom queries created in your system from the PSQRYDEFN PeopleTools ...