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();
  8. 第一句输出的是: "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“。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-06 18:22:43

js中作用域与作用域链详解的相关文章

js中的preventDefault与stopPropagation详解

本篇文章主要是对js中的preventDefault与stopPropagation进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助. 首先讲解一下js中preventDefault和stopPropagation两个方法的区别:preventDefault方法的起什么作用呢?我们知道比如<a href="http://www.baidu.com">百度</a>,这是html中最基础的东西,起的作用就是点击百度链接到http://www.baidu.co

js中for循环使用方法详解

大家好,今天我们来聊聊js中for循环,咱废话不多说直接进入主题: for语句是循环语句的一种用于创建一个循环,这是在开发中最常见的循环: for的语法for(初始值:条件判断:自身的改变){要重复执行的代码}: <script> var a=0;//定义一个变量 //循环6次,每次都执行a+1 for (i=0;i<6;i++){ a=a+1; console.log(a)//拿出a值看下变化过程 } </script> 下面我们来看下a的结果会是什么: 这就是a的变化过程

现代JS中的流程控制:详解Callbacks 、Promises 、Async/Await

JavaScript经常声称是_异步_.那是什么意思?它如何影响发展?近年来这种方法有何变化? 请思考以下代码: result1 = doSomething1(); result2 = doSomething2(result1); 大多数语言都处理每一行同步.第一行运行并返回结果.第二行在第一行完成后运行无论需要多长时间. 单线程处理 JavaScript在单个处理线程上运行.在浏览器选项卡中执行时,其他所有内容都会停止,因为在并行线程上不会发生对页面DOM的更改;将一个线程重定向到另一个URL

JS中的事件委托/代理详解

概述: 那什么叫事件委托呢?它还有一个名字叫事件代理,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件.那这是什么意思呢?网上的各位大牛们讲事件委托基本上都用了同一个例子,就是取快递来解释这个现象,我仔细揣摩了一下,这个例子还真是恰当,我就不去想别的例子来解释了,借花献佛,我摘过来,大家认真领会一下事件委托到底是一个什么原理: 有三个同事预计会在周一收到快递.为签收快递,有两种办法:一是三个人在公司门口等快递:二是委托给前台MM

js中 javascript:void(0) 用法详解(未整理)

javascript:void(0) 用于执行某些处理,但是不整体刷新页面的情况下使用. javascript:void(0)表示不做任何动作.如: <a href="javascript:void(0);" onclick="alert('ok');"></a> 这里表示这个链接不做跳转动作,执行onClick事件. 我想使用过ajax的都常见这样的代码: <a href="javascript:doTest2();void

JS中对Cookie的操作详解

前言 cookie设置 参数说明: name cookie 名称,key值 value 可选,cookie 值 expire 可选,过期时间,时间戳格式 path 可选,服务器端有效路径,/ 表示整个域名有效,默认为当前设置 cookie 时页面的路径 domain 可选,该 cookie 有效的域名 secure 可选.规定是否通过安全的 HTTPS 连接来传输 cookie. 代码的封装 (function(){ var cookieObj={ 'add':function(name, va

js中的原型与原型链详解

js中的原型与原型链详解 记住下面三句话就可以理解原型: 所有的函数数据类型都天生自带一个属性Prototype(原型)这个属性的值是一个对象,浏览器会默认给他开辟一个堆内存 在浏览器给prototype开辟的堆内存当中有一个天生自带的属性是constructor,这个属性存储的值是当前函数本身 每一个对象都有一个__proto__的属性,这个属性指向当前实例所属类的prototype(如果不能确定他是谁的实例,都是Object的实例) 原型链:如果引用构造函数的实例想要查找某个属性p的话: 首

struts2中&lt;s:checkboxlist/&gt;的用法详解

Html代码 选择角色<br> <s:checkboxlist list="#request.roleuserList" listKey="roleId" listValue="roleName" value="#request.rolelist.{roleId}" name="roleIds"></s:checkboxlist> 说明: 其中#request.roleu

Swift使用WKWebView在iOS应用中调用Web的方法详解

这篇文章主要介绍了Swift使用WKWebView在iOS应用中调用Web的方法详解,使用WKWebView便等于使用和Safari中相同的JavaScript解释器,用来替代过去的UIWebView,需要的朋友可以参考下 自从iOS8开始,Apple引入了WKWebView欲代替UIWebView.相比而言,WKWebView消耗内从更少,功能也更加强大.让我们来看看WKWebView怎么使用吧! 0.初始化(1)首先需要引入WebKit库 复制代码代码如下: #import <WebKit/

oc中字典的实现方法详解

一:字典的基本概念 Foundation中的字典(NSDictionary,NSMutableDictionary)是由键-值对组成的数据集合.正如,我们在字典里查找单词的定义一样. 通过key(键),查找的对应的value(值),key通常是字符串对象,也可以是其他任意类型对象.在一个字典对象中,key的值必须是唯一的. 此外,字典对象的键和值不可以为空(nil),如果需要在字典中加入一个空值,可以加入NSNull对象 二:不可变字典-NSDictionary 1:初始化(以一个元素和多个元素