Js作用域与作用域链详解[转]
一:函数作用域
先看一小段代码:
- var scope="global";
- function t(){
- console.log(scope);
- var scope="local"
- console.log(scope);
- }
- t();
(PS: console.log()是firebug提供的调试工具,很好用,有兴趣的童鞋可以用下,比浏览器+alert好用多了)
第一句输出的是: "undefined",而不是 "global"
第二讲输出的是:"local"
你可能会认为第一句会输出:"global",因为代码还没执行var scope="local",所以肯定会输出“global"。
我说这想法完全没错,只不过用错了对象。我们首先要区分Javascript的函数作用域与我们熟知的C/C++等的块级作用域。
在C/C++中,花括号内中的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的。而Javascript压根没有块级作用域,而是函数作用域.
所谓函数作用域就是说:-》变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
所以根据函数作用域的意思,可以将上述代码重写如下:
- var scope="global";
- function t(){
- var scope;
- console.log(scope);
- scope="local"
- console.log(scope);
- }
- t();
我们可以看到,由于函数作用域的特性,局部变量在整个函数体始终是由定义的,我们可以将变量声明”提前“到函数体顶部,同时变量初始化还在原来位置。
为什么说Js没有块级作用域呢,有以下代码为证:
- var name="global";
- if(true){
- var name="local";
- console.log(name)
- }
- console.log(name);
都输出是“local",如果有块级作用域,明显if语句将创建局部变量name,并不会修改全局name,可是没有这样,所以Js没有块级作用域。
现在很好理解为什么会得出那样的结果了。scope声明覆盖了全局的scope,但是还没有赋值,所以输出:”undefined“。
所以下面的代码也就很好理解了。
- function t(flag){
- if(flag){
- var s="ifscope";
- for(var i=0;i<2;i++)
- ;
- }
- console.log(i);
- console.log(s);
- }
- t(true);
输出:2 ”ifscope"
二:变量作用域
还是首先看一段代码:
- function t(flag){
- if(flag){
- s="ifscope";
- for(var i=0;i<2;i++)
- ;
- }
- console.log(i);
- }
- t(true);
- console.log(s);
就是上面的翻版,知识将声明s中的var去掉。
程序会报错还是输出“ifscope"呢?
让我揭开谜底吧,会输出:”ifscope"
这主要是Js中没有用var声明的变量都是全局变量,而且是顶层对象的属性。
所以你用console.log(window.s)也是会输出“ifconfig"
当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除
var name=1 ->不可删除
sex=”girl“ ->可删除
this.age=22 ->可删除
三:作用域链
先来看一段代码:
- name="lwy";
- function t(){
- var name="tlwy";
- function s(){
- var name="slwy";
- console.log(name);
- }
- function ss(){
- console.log(name);
- }
- s();
- ss();
- }
- t();
当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。然后从链表开头寻找变量name,很明显
name是"slwy"。
但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy"
下面看一个很容易犯错的例子:
- <html>
- <head>
- <script type="text/javascript">
- function buttonInit(){
- for(var i=1;i<4;i++){
- var b=document.getElementById("button"+i);
- b.addEventListener("click",function(){ alert("Button"+i);},false);
- }
- }
- window.onload=buttonInit;
- </script>
- </head>
- <body>
- <button id="button1">Button1</button>
- <button id="button2">Button2</button>
- <button id="button3">Button3</button>
- </body>
- </html>
当文档加载完毕,给几个按钮注册点击事件,当我们点击按钮时,会弹出什么提示框呢?
很容易犯错,对是的,三个按钮都是弹出:"Button4",你答对了吗?
当注册事件结束后,i的值为4,当点击按钮时,事件函数即function(){ alert("Button"+i);}这个匿名函数中没有i,根据作用域链,所以到buttonInit函数中找,此时i的值为4,
所以弹出”button4“。
四:with语句
说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。
看下面代码
- person={name:"yhb",age:22,height:175,wife:{name:"lwy",age:21}};
- with(person.wife){
- console.log(name);
- }
with语句将person.wife添加到当前作用域链的头部,所以输出的就是:“lwy".
with语句结束后,作用域链恢复正常。
Js作用域与作用域链详解[转]的更多相关文章
- JS作用域,作用域,作用链详解
前言 通过本文,你大概明白作用域,作用域链是什么,毕竟这也算JS中的基本概念. 一.作用域(scope) 什么是作用域,你可以理解为你所声明变量的可用范围,我在某个范围内申明了一个变量,且这个变量 ...
- 你不知道的JavaScript--Item15 prototype原型和原型链详解
用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了, ...
- JS中的event 对象详解
JS中的event 对象详解 JS的event对象 Event属性和方法:1. type:事件的类型,如onlick中的click:2. srcElement/target:事件源,就是发生事件的 ...
- js中鼠标滚轮事件详解
js中鼠标滚轮事件详解 (以下内容部分内容参考了http://adomas.org/javascript-mouse-wheel/ ) 之前js 仿Photoshop鼠标滚轮控制输入框取值中已使用 ...
- ext.js的mvc开发模式详解
ext.js的mvc开发模式详解和环境配置 在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开 ...
- 微信JS接口汇总及使用详解
这篇文章主要介绍了微信JS接口汇总及使用详解,十分的全面.详尽,包含分享到朋友圈,分享给朋友,分享到QQ,拍照或从手机相册中选图,识别音频并返回识别结果,使用微信内置地图查看位置等接口,有需要的小伙伴 ...
- “全栈2019”Java异常第十五章:异常链详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- js中中括号,大括号使用详解
js中中括号,大括号使用详解 一.总结 一句话总结:{ } 是一个对象,[ ] 是一个数组 1.js大括号{}表示什么意思? 对象 { } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或 ...
- js对象浅拷贝和深拷贝详解
js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具 ...
- amazeui中的js插件有哪些(详解功能)
amazeui中的js插件有哪些(详解功能) 一.总结 一句话总结: 二.amazeui中的js插件有哪些 1.UI 增强 警告框Alert 按钮交互Button 折叠面板Collapse 下拉组件D ...
随机推荐
- 新手浅谈C#关于abstract和interface
abstract:抽象类,是对某一类对象的抽象,继承抽象类的类和抽象类是属于关系 interface:接口,可以说是一种规范,继承接口的类表达则是,我继承了这个接口,我能做什么 举个常用的例子:抽象一 ...
- 抢滩登陆游戏android源码
是3d游戏开发技术详解与技术案例书里的一个例子 不多说上图{:soso_e113:} 源码下载地址:http://code.662p.com/view/2271.html <ignore_js_ ...
- 转:OpenCms 9.0.1汉化
LHD私人汉化. 1.完成安装OpenCms 2.如果正确安装,在浏览器输入以下地址即可打开登录页面(默认账号/密码:Admin/admin) http://localhost:8080/opencm ...
- 获取屏幕分辨率(C/C++)
C/C++获取屏幕分辨率的方法 int main(int argc, char* argv[]) { // 需要添加头文件: // #include <Windows.h> system( ...
- 分析MapReduce执行过程
分析MapReduce执行过程 MapReduce运行的时候,会通过Mapper运行的任务读取HDFS中的数据文件,然后调用自己的方法,处理数据,最后输出. Reducer任务会接收Mapper任务输 ...
- 新浪SAE URLRewrite(伪静态、重定向)详解
SAE全称Sina App Engine,真是一个好东西,他有很多优秀的特性,简单来说SAE就是一个简单高效的分布式Web服务开发.运行平台.支持现在常用的 PHP+Mysql 环境,在开发中难免会碰 ...
- 透过c的编程原则,来规范自己现在的一些编程习惯
1.合理的使用注释 注释为:/*…………*/ 注释有以下几种情况: 1) 版本.版权声明. 2) 函数接口说明. 3) 重要的代码或者段落显示. 注释注意: 1) 注释是对代码的解释,不是对文档.注释 ...
- (转)最强Android模拟器genymotion的安装与配置
Android开发人员都知道,原生的模拟器启动比较慢,操作起来也不流畅,还会出现莫名的问题.当然很多人都会选择直接使用android手机来开发,但是有时候需要在投影仪上演示程序的时候手机不太好做到吧. ...
- 限制<input>输入内容 只允许数字 或者 字母
只能输入数字: 有回显 <input onkeyup="value=value.replace(/[^\d]/g,'')"> 只能输入数字:无回显 <input ...
- C# 截取带路径的文件名字,扩展名,等等 的几种方法
C#对磁盘IO操作的时候,经常会用到这些,路径,文件,文件名字,文件扩展名. 之前,经常用切割字符串来实现, 可是经常会弄错. 尤其是启始位置,多少个字节,经常弄晕. 下面这种方法貌似比较简便: st ...