js的作用域和作用于链
来源:互联网 发布:网络诈骗按照什么罪 编辑:程序博客网 时间:2024/05/20 00:36
今天偶然看到闭包,右面开始看到作用域的问题,发现跟java之类的确实是不太一样。看到一篇超级好的文章,转载一下。
一直对Js的作用域有点迷糊,今天偶然读到JavaScript权威指南,立马被吸引住了,写的真不错。我看的是第六版本,相当的厚,大概1000多页,Js博大精深,要熟悉精通需要大毅力大功夫。
一:函数作用域
先看一小段代码:
- var scope=“global”;
- function t(){
- console.log(scope);
- var scope=“local”
- console.log(scope);
- }
- t();
var scope="global";function t(){ console.log(scope); var scope="local" console.log(scope);}t();
第一句输出的是: “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();
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);
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);
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);
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();
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>
<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“。
正确的做法应该怎样呢,再内嵌函数,现在访问的这个i就是(function(i){})里面这个i了,就能达到效果
function buttonInit() { for (var i = 1; i < 4; i++) { (function (i) { var b = document.getElementById("button" + i); b.addEventListener("click", function () { alert("Button" + i); }, false); })(i); }}
四:with语句
说到作用域链,不得不说with语句。with语句主要用来临时扩展作用域链,将语句中的对象添加到作用域的头部。
看下面代码
- person={name:“yhb”,age:22,height:175,wife:{name:“lwy”,age:21}};
- with(person.wife){
- console.log(name);
- }
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作用域链和变量的作用域
- js作用域和作用域链
- js作用域和作用域链
- js作用于和预编译
- 简述JS作用域、作用域链和闭包
- js作用域和作用域链心得
- 理解Js作用域和作用域链
- 关于js中的作用域和作用域链以及常见的问题和结果方法
- Js的作用域
- js的作用域
- js 和 java 作用域的区别
- JS的作用域和声明提前
- JS的解析过程和作用域
- [js点滴]JavaScript中的作用域及作用域链的意义和解释
- js的闭包与作用域/作用域链
- js的词法作用域、执行环境、作用域链
- c语言文件操作函数应用(2) ——学习整理
- 阿里2017实习生招聘笔试-编程题-过滤
- Qt程序显示出命令窗口
- opencv3.2 增加opencv_contrib组件
- [BZOJ4606][Apio2008]DNA(dp)
- js的作用域和作用于链
- 快排和希尔排序第一趟的结果
- Eclipse中10个最有用的快捷键组合
- POJ
- BZOJ1923: [Sdoi2010]外星千足虫
- 主题模型lda源码阅读
- mybatis遇到的一个问题Result Maps collection already contains value for com.schooldevice.dao.DeviceMapper.
- bootstrap bootbox 属性及用法
- 安卓中的View、SurfaceView和GLSurfaceView区别