精华内容
下载资源
问答
  • JavaScript 作用域 和作用域链作用域作用域链 作用域 作用域就是变量与函数的可访问范围,作用域控制着变量与函数的可见性和生命周期。换句话说,作用域决定了代码区块中变量和其他资源的可见性。 function fun() { ...
  • 当你进行函数的嵌套时,要注意实际上作用域链是发生变化的,这点可能看起来不太直观。你可把下面的代码置入firebug监视值的变化。
  • 图解javascript作用域链

    2020-12-02 14:18:41
    先来一段简单的javascript代码: ...1.javascript引擎会在页面加载脚本被执行时为每个函数创建一个作用域(执行上下文)及作用域链。 2.javascript引擎在产生这些作用域后,会创建一个堆栈。 3.将onload对应的
  • 闭包和作用域链是JavaScript中比较重要的概念,这两天翻阅了一些资料,把相关知识点给大家总结了以下。 JavaScript 采用词法作用域(lexical scoping),函数执行依赖的变量作用域是由函数定义的时候决定,而不是...
  • 在ES6之前,javascript...在了解作用域链之前,我们先了解一个执行期上下文的概念。 执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(即AO或GO),一个执行期上下文定义了一个函数的执行环境,函数
  • JavaScript中出现了一个以前没学过的概念——闭包。何为闭包?从表面理解即封闭的包,与作用域有关。所以,说闭包以前先说说作用域
  • 作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。任何程序...
  • 主要介绍了javascript作用域链(Scope Chain)用法,结合实例形式较为详细的分析了javascript作用域链(Scope Chain)的概念、功能与相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • javascript的作用域和作用域链是我学习最痛苦的一部分,因为我花了好多时间看了好多技术文档都没有理解.大体知道什么意思了,然后还说不出之所以然来. 通过我大量的测试和看技术文档总结了以下理解,虽然不是很有技术...
  • 虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,本文我会尽我所能用最简单的方式来解释作用域和作用域链,希望大家有所收获! 作用域(Scope) 1. 什么是作用域 作用域是在运行时代码中的某些特定部分中...
  • 作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。 ...
  • 作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。 ...
  • 作用域和作用域链在Javascript和很多其它的编程语言中都是一种基础概念。但很多Javascript开发者并不真正理解它们,但这些概念对掌握Javascript至关重要。 正确的去理解这个概念有利于你去写更好,更高效和更简洁的...
  • 作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了 层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错 在 JavaScript 中, 对象和函数同样也是变量。 在 JavaScript 中, 作用...
  • 作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理。今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript。 一、...
  • 作用域链(Scope Chain)

    2018-07-24 09:25:20
    我们已经知道一个执行上下文 的数据(变量、函数声明和函数的形参)作为属性存储在变量对象中。 同时我们也知道变量对象在每次进入上下文时创建,并填入初始值,值的更新出现在代码执行阶段。
  • 1. JavaScript函数的作用域链分为定义时作用域链和运行时作用域链; 2.函数被定义的时候,它有一个属性[[scope]]标明它的定义作用域链,定义时作用域链[[scope]]遵守这样的规则:一个函数的定义时作用域链[[scope]]...
  • 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。  1. 全局作用域...

    任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。在JavaScript中,变量的作用域有全局作用域和局部作用域两种。

      1.  全局作用域(Global Scope)

      在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

      (1)最外层函数和在最外层函数外面定义的变量拥有全局作用域,例如:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    var authorName="山边小溪";

    function doSomething(){

        var blogName="梦想天空";

        function innerSay(){

            alert(blogName);

        }

        innerSay();

    }

    alert(authorName); //山边小溪

    alert(blogName); //脚本错误

    doSomething(); //梦想天空

    innerSay() //脚本错误

      (2)所有末定义直接赋值的变量自动声明为拥有全局作用域,例如:

    1

    2

    3

    4

    5

    6

    7

    8

    function doSomething(){

        var authorName="山边小溪";

        blogName="梦想天空";

        alert(authorName);

    }

    doSomething(); //山边小溪

    alert(blogName); //梦想天空

    alert(authorName); //脚本错误

      变量blogName拥有全局作用域,而authorName在函数外部无法访问到。

      (3)所有window对象的属性拥有全局作用域

      一般情况下,window对象的内置属性都拥有全局作用域,例如window.name、window.location、window.top等等。

      1.  局部作用域(Local Scope)  

      和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域,例如下列代码中的blogName和函数innerSay都只拥有局部作用域。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    function doSomething(){

        var blogName="梦想天空";

        function innerSay(){

            alert(blogName);

        }

        innerSay();

    }

    alert(blogName); //脚本错误

    innerSay(); //脚本错误

    作用域链(Scope Chain)

      在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

      当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:

    1

    2

    3

    4

    function add(num1,num2) {

        var sum = num1 + num2;

        return sum;

    }

      在函数add创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分):

     

    JavaScript作用域链

     

      函数add的作用域将会在执行时用到。例如执行如下代码:

    1

    var total = add(5,10);

      执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

      这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:

     

    JavaScript作用域链

     

      在函数执行过程中,没遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。

    作用域链和代码优化

      从作用域链的结构可以看出,在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。如上图所示,因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。一个好的经验法则是:如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。例如下面的代码:

    1

    2

    3

    4

    5

    function changeColor(){

        document.getElementById("btnChange").onclick=function(){

            document.getElementById("targetCanvas").style.backgroundColor="red";

        };

    }

      这个函数引用了两次全局变量document,查找该变量必须遍历整个作用域链,直到最后在全局对象中才能找到。这段代码可以重写如下:

    1

    2

    3

    4

    5

    6

    function changeColor(){

        var doc=document;

        doc.getElementById("btnChange").onclick=function(){

            doc.getElementById("targetCanvas").style.backgroundColor="red";

        };

    }

      这段代码比较简单,重写后不会显示出巨大的性能提升,但是如果程序中有大量的全局变量被从反复访问,那么重写后的代码性能会有显著改善。

    改变作用域链

      函数每次执行时对应的运行期上下文都是独一无二的,所以多次调用同一个函数就会导致创建多个运行期上下文,当函数执行完毕,执行上下文会被销毁。每一个运行期上下文都和一个作用域链关联。一般情况下,在运行期上下文运行的过程中,其作用域链只会被 with 语句和 catch 语句影响。

      with语句是对象的快捷应用方式,用来避免书写重复代码。例如:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    function initUI(){

        with(document){

            var bd=body,

                links=getElementsByTagName("a"),

                i=0,

                len=links.length;

            while(i < len){

                update(links[i++]);

            }

            getElementById("btnInit").onclick=function(){

                doSomething();

            };

        }

    }

      这里使用width语句来避免多次书写document,看上去更高效,实际上产生了性能问题。

      当代码运行到with语句时,运行期上下文的作用域链临时被改变了。一个新的可变对象被创建,它包含了参数指定的对象的所有属性。这个对象将被推入作用域链的头部,这意味着函数的所有局部变量现在处于第二个作用域链对象中,因此访问代价更高了。如下图所示:

     

    JavaScript作用域链

     

      因此在程序中应避免使用with语句,在这个例子中,只要简单的把document存储在一个局部变量中就可以提升性能。

      另外一个会改变作用域链的是try-catch语句中的catch语句。当try代码块中发生错误时,执行过程会跳转到catch语句,然后把异常对象推入一个可变对象并置于作用域的头部。在catch代码块内部,函数的所有局部变量将会被放在第二个作用域链对象中。示例代码:

    1

    2

    3

    4

    5

    try{

        doSomething();

    }catch(ex){

        alert(ex.message); //作用域链在此处改变

    }

      请注意,一旦catch语句执行完毕,作用域链机会返回到之前的状态。try-catch语句在代码调试和异常处理中非常有用,因此不建议完全避免。你可以通过优化代码来减少catch语句对性能的影响。一个很好的模式是将错误委托给一个函数处理,例如:

    1

    2

    3

    4

    5

    try{

        doSomething();

    }catch(ex){

        handleError(ex); //委托给处理器方法

    }

      优化后的代码,handleError方法是catch子句中唯一执行的代码。该函数接收异常对象作为参数,这样你可以更加灵活和统一的处理错误。由于只执行一条语句,且没有局部变量的访问,作用域链的临时改变就不会影响代码性能了。

    展开全文
  • 作用域链:作用域有上下级关系,上下级关系的确定就看函数在哪个作用域下创建的,当代码在一个环境中执行,会创建变量对象的一个作用域链。当访问变量时,会一级一级向上寻找变量定义,直到找到他。若一直寻找到...
  • 作用域和作用域链 精解

    千次阅读 2019-05-24 17:24:58
    **作用域(scope):一个变量的可用范围 2种: 全局作用域 :任何地方都可以访问,反复使用 函数作用域(局部作用域):仅在函数内部可访问,不能反复使用 例子: var a=10; function fun() { var a=100;...

    作用域(scope):一个变量的可用范围

    2种:
    全局作用域 :任何地方都可以访问,反复使用

    函数作用域(局部作用域):仅在函数内部可访问,不能反复使用
    例子:

    var a=10;
    	function fun()
    	{
    		var a=100;
    		a++;
    		console.log(a);
    	}
    	fun();//101
    
    	console.log(a);//10
    

    函数的生命周期

    作用域前言
    每个函数都有自己的执行环境,(首先,所有的环境会形成 一个环境栈)。当代码执行进入一个函数后(也就是开始执行函数里的代码了),函数的执行环境会被推进(push)这个大的环境栈中,当函数执行完成后,大的环境栈就会将该函数的环境栈挤出(pop),并将控制权交还给原先的执行环境,就是在回到原来的执行流上去了。

    当代码在执行环境中执行时,变量对象的作用域链就被创建了。作用域链的目的就是为执行环境有权访问的变量和函数提供有序的访问,不让其乱套。有顺序的来。作用域链的前端(或最接近的,最里面的,最里层的)始终都是当前正在执行的代码所在的执行环境的变量对象。

    如果执行环境是函数,则将其活动对象(activation object)简称:AO 作为变量对象。活动对象最开始只包含一个变量,arguments对象(在全局环境中不存在)。这就是该函数的作用域链上最前端的,最里面的了,该作用域链上下一个变量对象就是来自于包含(即外部)环境,再下一个也是来自再下一个外部环境,一层一层的逐渐的往外剥皮,知道最外面的全局环境。全局环境的变量对象就是该作用域链上最后一个对象了。

    注释:’‘函数的作用域链上最前端的,最里面’'指的是预编译将全局对象中的声明和函数(执行函数列表参数,声明变量,函数内部嵌套的函数)提升到最上方,从上至下执行。-----可以百度参考变量提升和函数提升,或js预编译

    1、开始执行前
    1-1 创建执行环境栈(ECS数组):临时保存正在执行的函数的环境
    1-2 向执行环境栈中加入第一个默认函数main()
    1-3.创建全局作用域对象window

    2、定义函数时
    2-1.创建函数对象,封装定义
    2-2. 声明函数名变量,引用函数对象
    2-3. 函数对象的scope属性引用回,创建函数时的作用域

    在这里插入图片描述
    3、调用函数时
    3-1 ESC中加入一个新的元素(执行环境),记录新函数调用
    3-2 创建一个活动对象,保存本次函数调用用到的局部变量
    3-3 ESC新执行环境元素,引用活动对象
    3-4 活动对象中的parent属性引用函数的scope指向的父级作用域对象
    3-5 在执行过程中:优先使用活动对象中的局部变量
    3-6 局部中没有,才延parent向父级作用域找*
    在这里插入图片描述
    ** 4、调用函数后
    4-1 执行环境栈中本次函数的执行环境出栈
    4-2 导致活动对象被释放 导致局部变量一同释放

    在这里插入图片描述

    作用域链

    作用域链*:由多级作用域连续引用形成的链式结果
    掌管一切变量的使用顺序: 先在局部找,没有,就延作用域向父级作用域找

    在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

    当一个函数创建后,它实际上保存一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:

    function func() {
    var num = 1;
    alert(num);
    }
    func();

    在函数func创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分):

    在这里插入图片描述

    执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

    这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:
    在这里插入图片描述
    外部环境不能访问内部环境的任何变量和函数。即可以向上搜索,但不可以向下搜索。

    可以理解为什么有关于作用域链的定义说,作用域链是一群对象,或者对象列表(链表)。也有总结如下:

    对于javascript最顶层的代码(不包含任何函数定义内的代码),其作用域链只包含一个对象:即全局对象。
    对于不包含嵌套函数的函数,其作用域链包含两个对象:其自身的变量对象和全局变量对象。
    对于包含了嵌套函数的函数,其作用域包含至少三个对象:自身的变量对象,外层的(将自身嵌套的),全局变量对象。

    展开全文
  • 之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时候发现作用...
  • 本文实例讲述了JavaScript词法作用域与作用域链。分享给大家供大家参考,具体如下: 一、作用域 域表示的就是范围,即作用域,就是一个名字在什么地方可以使用,什么时候不能使用。想了解更多关于作用域的问题推荐...
  • js底层原理作用域和作用域链

    千次阅读 2019-07-31 22:05:18
    [[scope]]指的是我们所说的作用域(作用域链),其中存储了运行期期上下文的集合。每一个函数都有一个作用域。 运行期上下文:当函数执行的过程之前,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了...

    1、作用域([[scope]])

    • [[scope]]:每一个js函数都是一个对象,对象中有些属性我们可以访问,但是有些不可以,这些属性仅供js引擎存取,[[scope]]就是其中的一个。[[scope]]指的是我们所说的作用域(作用域链),其中存储了运行期期上下文的集合。每一个函数都有一个作用域。
    • 运行期上下文:当函数执行的过程之前,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行对应执行期上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行期上下文,当函数执行完毕,它所产生的执行期上下文会被销毁。
    • 看不懂概念不要紧,可以看下面的例子,然后看概念就会理解。
    • 如果不知道执行期上下文的可以看:
      https://blog.csdn.net/weixin_44588495/article/details/86616034

    2、作用域链

    • [[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

    3、要知道

    function Person(){
    
    }
    console.log(Person.name);
    console.log(Person.prototype);
    
    • 这里的Person.name等就是可以访问的,但是Person.[[scope]]就是我们访问不到的。
    • 这里每次调用都会产生一个新的AO对象。
        function test(){
            
        }
        test() -> 产生一个AO{} 用完销毁
        test() -> 产生一个AO{} 用完销毁
    

    3、例子

    function a(){
         function b(){
             var b = 234;
         }
         var a = 123;
         b();
    }
     var glob = 100;
     a();
    
    • a函数定义时,产生了一个[[scope]],这里实际上只有一个GO,全局的作用域。
      在这里插入图片描述
    • a在要执行之前,产生了一个执行期上下文。在这里,新创建的AO是作用域的顶端,我们在查找变量的时候就是沿着作用域链去查找变量,从顶端开始。这也就是为什么,在函数调用时,先查找自己是否含有这个属性,如果没有这个属性就去父级查找,这就是原理。这就是a函数的作用域链了。可以理解为[[scope]]为一个数组。函数本身的预编译形成AO永远是放在最顶端。
      在这里插入图片描述
    • 由于a函数的执行内部执行b(),所以b函数只在执行之前又产生了一个执行期上下文。所以b的作用域链直接基于a的作用域链。
    • b函数被创建时的作用域环境:
      在这里插入图片描述
    • b()执行之前进行预编译,形成的作用域链。
      在这里插入图片描述
    • 当b函数查找变量的时候,自顶向下查找变量。
    这里是为下一篇闭包铺垫理论知识。
    展开全文
  • 本文实例分析了JavaScript函数作用域链。分享给大家供大家参考。具体分析如下: 作用域链: JavaScript的每个函数function都有自己的作用域,使用Active Object(简称AO)活动对象来保存,在相互嵌套的函数中形成了...
  • 本文实例讲述了JavaScript作用域链。分享给大家供大家参考,具体如下: 跟其他语言一样,变量和函数的作用域揭示了这些变量和函数的搜索路径。对于JavaScript而言,理解作用域更加重要,因为在JavaScript中,作用域...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 276,991
精华内容 110,796
关键字:

作用域链