JavaScript作用域学习笔记

作者: 7091a52ac9e5 | 来源:发表于2016-03-13 12:36 被阅读263次

@(JS技巧)[JavaScript, 作用域]

JavaScript作用域学习笔记

概念:

作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。

分类:

全局作用域(Global Scope)

定义:
在代码中任何地方都能访问到的对象拥有全局作用域

出现的情况:

  1. 最外层函数和在最外层函数外面定义的变量拥有全局作用域;
  2. 所有未定义直接赋值的变量会自动声明为全局作用域;
  3. 所有window对象的属性;
局部作用域

定义
只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域;

作用域链

定义:
JavaScript有一个内部属性称为Scope,由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

在JS中,作用域的概念和其他语言差不多, 在每次调用一个函数的时候 ,就会进入一个函数内的作用域,当从函数返回以后,就返回调用前的作用域.

js作用域的执行过程
  1. 任何执行上下文时刻的作用域, 都是由作用域链(scope chain)来实现。
  2. 在一个函数被定义的时候, 会将它定义时刻scope chain链接到这个函数对象的[[scope]]属性.
  3. 在一个函数对象被调用的时候,会创建一个活动对象(也就是一个对象), 然后对于每一个函数的形参,都命名为该活动对象的命名属性, 然后将这个活动对象做为此时的作用域链(scope chain)最前端, 并将这个函数对象的[[scope]]加入到scope chain中.
作用域链
函数执行的赋值过程

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

注意: 因为函数对象的[[scope]]属性是在定义一个函数的时候决定的, 而非调用的时候,

JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里

Javascript的预编译
  1. JS是一种脚本语言, JS的执行过程, 是一种翻译执行的过程.
  2. 在JS中, 是有预编译的过程的, JS在执行每一段JS代码之前, 都会首先处理var关键字和function定义式(函数定义式和函数表达式).
  3. 在调用函数执行之前, 会首先创建一个活动对象, 然后搜寻这个函数中的局部变量定义,和函数定义, 将变量名和函数名都做为这个活动对象的同名属性, 对于局部变量定义,变量的值会在真正执行的时候才计算, 此时只是简单的赋为undefined.
  4. 对于函数定义式, 会将函数定义提前. 而函数表达式, 会在执行过程中才计算.
  5. JS的预编译是以段为处理单元的…
作用域链和代码优化

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

function changeColor(){
    document.getElementById("btnChange").onclick=function(){
        document.getElementById("targetCanvas").style.backgroundColor="red";
    };
}

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

function changeColor(){
    var doc=document;
    doc.getElementById("btnChange").onclick=function(){
        doc.getElementById("targetCanvas").style.backgroundColor="red";
    };
}

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

改变作用域链

有两种方法可以改变作用域链:

  1. with:应该避免,使作用域链更长,有性能影响;
with的作用域链
  1. try-catch语句中的catch语句:
    try{
    doSomething();
}catch(ex){
    alert(ex.message); //作用域链在此处改变
}

一旦catch语句执行完毕,作用域链机会返回到之前的状态。
try-catch语句在代码调试和异常处理中非常有用,因此不建议完全避免。

参考文献

JavaScript 开发进阶:理解 JavaScript 作用域和作用域链
JavaScript作用域链原理

相关文章

  • JavaScript作用域学习笔记

    @(JS技巧)[JavaScript, 作用域] JavaScript作用域学习笔记 概念: 作用域就是变量与函数...

  • javascript 作用域

    javascript 作用域 本文是作者的学习笔记、主要是给大家说说作用域在javascript中是怎么一回事、有...

  • JavaScript 学习笔记——作用域

    本人水平有限,如有叙述不当或者错误之处,望各位指出,十分感谢! 作用域 我们要知道,在 JavaScript 中,...

  • javascript作用域学习笔记

    a.作用域属性是在定义函数的时候决定的,不是在调用函数的时候决定。//JavaScript中的函数运行在它们被定义...

  • JavaScript作用域学习笔记

    作用域链 作用域的原理: ”JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里.”...

  • JavaScript作用域学习笔记

    总结来说很简单: 函数运行在定义时的作用域中 变量查找会从当前作用域开始查找,找不到则到下一层作用域查找,直到找到...

  • JavaScript作用域学习笔记

    作用域是变量与函数的可访问范围,作用域控制着变量与函数的可见性和生命周期。变量的作用域有两种:全局作用域和局部作用...

  • 07-JavaScript作用域和预解析

    JavaScript作用域 JavaScript中有全局作用域和局部作用域 相同作用域内不能有同名的变量和函数 不...

  • JavaScript 作用域和作用域链

    JavaScript 作用域 作用域就是变量与函数的可访问范围。在JavaScript中,变量的作用域有全局作用域...

  • 2019-11-11-本周学习周报

    学习总览 JavaScript 函数作用域、块级作用域 变量提升、函数提升 CSS 新增属性transition ...

网友评论

    本文标题:JavaScript作用域学习笔记

    本文链接:https://www.haomeiwen.com/subject/cqzxlttx.html