资讯专栏INFORMATION COLUMN

Javascript执行环境和作用域的注意要点

CKJOKER / 980人阅读

摘要:所以,全局执行环境的变量对象始终都是作用域链中的最后一个对象。搜索过程从作用域链的最前端开始,逐级向后回溯,直到找到标识符为止。查询标识符搜索过程就是沿作用域链向上查询的过程。

执行环境

执行环境就是“环境”,是js中最重要的概念。执行环境定义了变量或函数有权访问的其他数据。每个执行环境都有一个与之相关的变量对象(我们编写的代码无法访问这个对象)

全局执行环境(是最外围的执行环境。在Web浏览器中,全局执行环境是Window对象。某个执行环境中的所有代码执行完毕后,该环境会被销毁;全局执行环境则直到应用程序退出,如关闭网页或浏览器时才会被销毁。环境被销毁时,保存在其中的所有变量和函数定义也都会被销毁。

执行环境(当执行流进入一个函数时,函数的环境会被推入一个环境栈中。当函数执行之后,环境栈将其弹出,把控制权返回给之前的执行环境。)

作用域链(当代码在一个环境中执行时,会创建变量对象的一个作用域链。其用途是保证对执行环境有权访问的所有变量和函数的有序访问。一个包含环境的变量对象到另一个包含环境的变量对象,最后到全局执行环境的变量对象。所以,全局执行环境的变量对象始终都是作用域链中的最后一个对象。

标识符解析

标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程从作用域链的最前端开始,逐级向后回溯,直到找到标识符为止。如:

var color = "blue";

function changeColor(){
    if (color === "blue"){
        color = "red";
    }else {
        color = "blue";
    }
}

changeColor();

document.write("Color is now " + color);

在上面的例子中,函数changeColor()的作用域链包含两个对象:changeColor()函数自己的变量对象和全局环境的变量对象。(可以在函数内部访问变量color,就是因为可以在这个作用域链中找到它。)在看另一个例子:

var color = "blue";

function changeColor(){
    var anotherColor = "red";
    
    function swapColors(){
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
        //这里可以访问tempColor anotherColor color
    }
    
    //这里可以访问anotherColor color
}

//这里可以访问color
changeColor();

执行环境:3个,全局环境,changeColor()的局部环境和swapColors()的局部环境。

全局环境:一个变量color 和一个函数changeColor()。

changeColor()环境:一个变量anotherColor 和一个swapColors()函数。(可以访问全局变量中的color)

swapColors()环境:一个变量tempColor。(可以访问全局环境中的color 和changeColor()环境中的anotherColor变量。)

swapColors()内部可以访问到其他两个环境中的所有变量,因为其他两个环境是它的父执行环境*

上面的例子可以用作用域链表示出来:(话说有没有网友可以推荐下好用的图床呀?纯文本画画还真麻烦。)

window(全局环境)
    |
    |-color(变量)
    |
    |-changeColor()(局部环境)
        |
        |-anotherColor(变量)
        |
        |-swapColors()(局部环境)
            |
            |-tempColor(变量)
            

内部环境可以通过作用连访问所有的外部环境,但外部环境不能访问内部环境的任何变量和函数。就是说,每个环境都可以向上搜索作用域链,但任何环境都不能向下搜索作用域链。

延长作用域链

虽然执行环境的类型总共只有全局和局部(函数)两种,但是还是可以使用下面两种办法来延长作用域链。

try-catch 语句的catch 块;

with 语句

上面这种方法就是当执行流进入下列任何一个语句时,作用域链就会得到加长。如:

function log(){
    var string = "the location is: "
    
    with(location){
        var url = string + href;
    }
    
    return url;
}

document.write(log());
//the location is: ... Volumes/TOSHIBA/project/tester/repetition.html

这里面使用with 语句,可以看到return url 语句可以访问到with 语句中的url 变量。再看下面的例子:

function log(){
    var string = "the location is: "
    function href(){
        var url = string + location.href;
    }
    return url;
}
document.write(log());
// ReferenceError: Can"t find variable: url

如果是普通的function 函数则不能访问url 变量。

另外,在IE8 中,即使是在catch 块的外部也可以访问到错误对象。IE9 修复了这个问题。

没有块级作用域

JavaScript 不像C 语言中,由花括号封闭的代码块都有自己的作用域。JavaScript 没有块级作用域。如:

if (true){
    var color = "blue";
}
document.write(color); //"blue"

花括号以外的地方仍然可以访问话括号内的变量。

尤其应该在for 循环中注意这个特性:

for (var i = 0; i < 5; i ++){
    var count = i + i;
}
document.write(count); //8
声明变量

如果初始化变量时没有使用var 声明,该变量会被添加到全局环境中去。如:

function count(x,y){
    var result = x + y;
}
count(1,2);
document.write(result); // ReferenceError: Can"t find variable: result

function count(x,y){
    result = x + y;
}
count(1,2);
document.write(result); //3

在编写代码的过程中,不声明而直接初始化变量是一个常见的错误做法。很可能会导致以外。建议在初始化变量之前,一定要先声明。在严格模式下,初始化未经声明的变量会导致错误。

查询标识符

搜索过程就是沿作用域链向上查询的过程。如:

var result = 1;
function func(){
    document.write(result);
}
func(); //1

如果局部环境中存在着同名标识符,就不会使用位于父环境中的标识符。如:

var result = 2;
function func(){
    var result = 1;
    document.write(result);
}
func(); //1
document.write(window.result); //2 或者直接用下面的代码返回最初的result
document.write(result);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86162.html

相关文章

  • 前端技术要点

    摘要:函数节流使得一定时间内只触发一次函数。区别函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。这样的场景,就适合用节流技术来实现。需要注意一点,服务端也要支持。 原文 https://github.com/Ritr/mark/... js 闭包要理解闭包,首先要知道javascript的作用域。通常ja...

    Loong_T 评论0 收藏0
  • 深入理解javascript原型闭包

    摘要:深入理解原型和闭包王福朋博客园深入理解原型和闭包一切都是对象原文链接本文要点一切引用类型都是对象,对象是属性的集合。每个对象都有一个,可称为隐式原型。另外注意,构造函数的函数名第一个字母大写规则约定。 深入理解javascript原型和闭包 王福朋 - 博客园 —— 《 深入理解javascript原型和闭包》 1. 一切都是对象 原文链接:http://www.cnblogs.com...

    jemygraw 评论0 收藏0
  • JavaScript引用类型——“Function类型”的注意要点

    摘要:类型每个函数都是类型的实例。如以上代码可行,是因为在代码开始值钱,解析器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中去。也可同时使用函数声明和函数表达式,但在浏览器中会出错。 Function 类型 每个函数都是Function 类型的实例。函数名实际上就是一个指向函数对象的指针,不会与某个函数绑定。 函数声明方式创建Function,语法如下: functi...

    fantix 评论0 收藏0
  • JavaScript DOM扩展——“HTML5”的注意要点

    摘要:如他返回的对象是。方法,这个方法用于确定文档是否获得了焦点。另外,需要注意的是,该属性插入元素并不会执行其中的脚本。在中,方法接收一个字符串,返回一个经过无害处理后的版本。属性同样的,在读模式下返回调用它的元素及所有子节点的标签。 与类相关的扩充 getElementsByClassName()方法 接收一个参数,即一个或多个类名的字符串。如: console.log(documen...

    cppowboy 评论0 收藏0
  • JavaScript DOM扩展——“HTML5”的注意要点

    摘要:如他返回的对象是。方法,这个方法用于确定文档是否获得了焦点。另外,需要注意的是,该属性插入元素并不会执行其中的脚本。在中,方法接收一个字符串,返回一个经过无害处理后的版本。属性同样的,在读模式下返回调用它的元素及所有子节点的标签。 与类相关的扩充 getElementsByClassName()方法 接收一个参数,即一个或多个类名的字符串。如: console.log(documen...

    Donald 评论0 收藏0

发表评论

0条评论

CKJOKER

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<