一. Javascript的作用域,大坑!

  1. JS作用域奇怪表现之一:预编译

在其他的语言里我们如果使用一个变量在声明其之前,是会报错的,但是在js里面却不一定,比如:

 function f1() {
console.log(aaa);
var aaa = 1;
} f1();

这里解释器就不会报错,而是会输出一个undefined出来,也就是声明了但是没有初始化赋值的效果。原有在于js的解释器从上到下执行,到f1这里的时候虽然不会执行,但是已经把函数放到内存里了,顺便aaa也在内存里了(相当于已经有个 var aaa;了)。但是如果彻底没能让解释器找到个变量还是会报错的,比如:

function f1() {
console.log(aaa);
}
f1();

  

  2. JS没有块级作用域!

我们知道在其他语言中,如果在一个块级空间(比如if语句的内部、for语句的内部等等)内定义一个局部变量,其作用域就只在这个块内,出了块以后就没有了,但是JS并不是这样,它没有块级的作用域,其作用域是以function为单位的(貌似不少脚本语言都酱紫?比如python...),只要在一个function里面定义的,即使出了一些块也是能找到的,比如:

 function f1(){
if (1 === 1){
var aa = 123;
}
console.log(aa);
}

这样是能够正确输出结果123的。

再来看个行为诡异的例子:

 function f1(){
for(var i=0; i<10; i++){ }
console.log(i);
}
f1();

例子的结果是10!赶脚和其他语言真是差距太大了...原因是首先function内是同一作用域所以能够输出i而非undefined,此外由于真正退出for循环的时候,其实i已经循环加到10了,所以这才是其的值。

然后继续看更诡异的例子...

 function f1(){
for(var i=0; i<3; i++){
setInterval(function (){
console.log(i);
}, 1000);
}
}
f1();

最后定时器输出的全部都是3。这是因为在调用f1的时候,循环完创建3个定时器并给它们绑定匿名函数的后,退出循环的时候,i已经是3了,而此时用于输出的匿名函数还并未运行。直到定时器启动它们,匿名函数开始从它们自己的作用域链开始寻找,其函数内部没有变量i,就找到了f1函数内部的变量i,而此时i已经是3了。所以之后输出的都是3。也许像下面这样分开来不用匿名函数看起来逻辑更清晰:

 function f1(){
for(var i=0; i<3; i++){
function f2 (){
console.log(i);
}
setInterval(f2, 1000);
}
}
f1();

这样看起来setInterval就和分开了。

再看一个类似的例子,先在html中搞3个按钮:

 <div id="btns">
<input type="button" value="btn1"/>
<input type="button" value="btn2"/>
<input type="button" value="btn3"/>
</div>

然后在js里面给三个按钮都绑定上点击事件:

 var btns = document.getElementById('btns').children;
for (var i=0; i< btns.length; i++){
btnbtn = btns[i];
btnbtn.onclick = function (){
console.log(i);
};
}

这样最后按任何按钮输出的也都是3,原理和之前一样,即循环绑定的时候,你们函数并未执行,而当点击执行的时候,i已经是3了。

  3. JS的作用域链

先看一个例子:

 aa = 1;
function f1(){
var aa = 2;
function f2() {
alert(aa);
}
return f2;
}
var ret = f1();
ret();

这个例子的输出是2而非1;这里的结果和python里的闭包非常相似;因为JS里面有个作用域链。以上面的例子为例,链的顺序是从全局->外层函数f1->内层函数f2,

当运行的时候要查找变量,就会逆着这个链,从最内层向外找;此处因为在定f2中找不到aa,就找到了f1中的aa,而f1中的aa值是之前执行f1函数时候里面已经定义好的了,所以就是2了;此时已经找到aa,就不会继续往上找全局的aa的值了。再看个例子:

 aa = 1;
function Bar(){
console.log(aa);
} function Func(){
var aa = 2;
return Bar;
} var ret = Func();
ret();

这里的结果是1!原有是其实这部分代码有两个作用域链,函数Bar的作用域链就是全局->Bar,而Func的是全局->Func,需要注意的是Bar是定义在全局里的,虽然在Func里面return了Bar,但是它的作用域还是外面的!所以虽然执行Func返回的Bar,Func内的aa的值为2,但是真正运行ret()来执行Bar函数的时候,寻找aa的路径还是从Bar内部,然后直接就找到全局里面的aa了,所以结果为1.

施工中。

JS与Jquery学习笔记(一)的更多相关文章

  1. JS与Jquery学习笔记(二)

    一. JS 的面向对象 JS没有类,其类就用function来代替如下所示: function Cat(name, color){ this.name=name; this.color=color; ...

  2. Js、jquery学习笔记

    end() 方法 重新定位到上次操作的元素,一般与siblings()一起使用,操作其兄弟元素.如:$(this).addClass("highlight").children(& ...

  3. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  4. jQuery学习笔记(一)jQuery选择器

    目录 jQuery选择器的优点 基本选择器 层次选择器 过滤选择器 表单选择器 第一次写博客,希望自己能够长期坚持,以写博客的方式作为总结与复习. 最近一段时间开始学习jQuery,通过写一个jQue ...

  5. jQuery 学习笔记

    jQuery 学习笔记   一.jQuery概述    宗旨: Write Less, Do More.    基础知识:        1.符号$代替document.getElementById( ...

  6. jQuery学习笔记 - 基础知识扫盲入门篇

    jQuery学习笔记 - 基础知识扫盲入门篇 2013-06-16 18:42 by 全新时代, 11 阅读, 0 评论, 收藏, 编辑 1.为什么要使用jQuery? 提供了强大的功能函数解决浏览器 ...

  7. JQuery学习笔记——层级选择器

    JQuery学习笔记--层级选择器 上一篇学习了基础的五种选择,分别是id选择器,class选择器,element选择器,*选择器 和 并列选择器.根据手册大纲,这篇学习的是层级选择器. 选择器: 1 ...

  8. jQuery学习笔记之Ajax用法详解

    这篇文章主要介绍了jQuery学习笔记之Ajax用法,结合实例形式较为详细的分析总结了jQuery中ajax的相关使用技巧,包括ajax请求.载入.处理.传递等,需要的朋友可以参考下 本文实例讲述了j ...

  9. jQuery学习笔记之jQuery的Ajax(3)

    jQuery学习笔记之jQuery的Ajax(3) 6.jQuery的Ajax插件 源码地址: https://github.com/iyun/jQueryDemo.git ------------- ...

随机推荐

  1. oracle 几个不常用的关键字

    ntile (n)是分析函数,n是吧窗体的数据分成几组. sys_connect_by_path 用来列转行 connect_by_isleaf 判断层级查询是否为叶子节点. siblings 用来层 ...

  2. Android Studio新建一个HelloWorld 程序(App)

    Android Studio新建一个HelloWorld程序(App) 新建 或者直接启动程序(注:如果已有程序,此方法会直接打开最近一次关闭从程序) 更改App名 选择App运行平台 选择模板 更改 ...

  3. 通过反射绑定事件_Office Visio

    花了好几个小时才Try出来,记录一下: //反射获取Visio.Application,此处没有判断是否有安装Visio            mVisioType = System.Type.Get ...

  4. QuickHit快速击键小程序 --S2.4.5

    我们现在要做一个项目 一个小小的程序 叫做快速击键 很明了的目的 就是在规定时间内,每次出现一组字母的组合,这个字母只能在DFJK中生成 然后输入相应的文字,按回车 自动判断输入的是否正确 在规定时间 ...

  5. 网络TCp数据的传输设计(黏包处理)

    //1.该片为引用别人的文章:http://www.cnblogs.com/alon/archive/2009/04/16/1437599.html 解决TCP网络传输"粘包"问题 ...

  6. 查询AD账号的SID

    在非域控的计算机上可以查询所用AD用户的SID,不过现成的工具不能直接实现此目的,我们需要在这些计算机上安装RSAT(远程服务器管理工具),然后使用dsquery和dsget命令,来快速查询AD用户的 ...

  7. C# Using 用法

    using 语句允许程序员指定使用资源的对象应当何时释放资源.为 using 语句提供的对象必须实现 IDisposable 接口.此接口提供了 Dispose 方法,该方法将释放此对象的资源. 一起 ...

  8. String和string的区别(C#)

    从位置讲: 1.String是.NET  Framework里面的String,小写的string是C#语言中的string 2.如果把using System;删掉,没有大写的String了,Sys ...

  9. [刘阳Java]_MyBatis_动态SQL标签用法_第7讲

    1.MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. 2.MyBatis中用于实现动态SQL的元素主要有 if choose(when,otherwi ...

  10. Android.mk 基本应用

    如果是在android源码里面编译我们自己的应用,就需要这个android.mk文件,这个文件就告诉android系统应用如何来编译这个应用以及这个应用它所依赖哪些文件等等信息.我对android.m ...