JavaScript-执行环境

JavaScript的执行环境定义了变量和函数有权访问其他数据,修改它们的值。每一个执行环境有一个变量对象,定义了环境中的所有变量和函数。全局执行环境是我们最外边的一个执行环境,在web浏览器,这个全局的执行环境就是我们的window对象。每一个函数都有自己的执行环境,当执行流执行一个函数的时候,我们的JavaScript就会把当前的执行环境推进环境栈,执行完里面的代码就会从环境栈弹出,把控制权交给前一个执行环境。

我们来说说作用域链。其实作用域链定义了我们执行环境有权访问的所有变量和函数。在前面说到,我们有一个环境栈,环境栈最前面的变量对象的下一个变量对象来自包含环境,依次类推。所以栈低变量对象是全局执行环境的。

内部环境可以通过作用域链访问外部环境的所有的变量和函数,但是外部环境不能访问内部环境的任何变量和函数,这也是闭包的原理。

标识符解析也就是沿着作用域链一级一级地搜索标识符的过程,先从作用域链的前端开始,逐级向后回溯,直到找到为止,如果找不到就会报错。

我们拿一道网易的前端机试题目来帮助理解这个知识点:
在下面的html的结构下,写出点击其中一个<li>标签当前背景色改变红色,同胞的颜色为白色

<ul id="father">
    <li>我是第一</li>
    <li>我是第二</li>
    <li>我是第三</li>
    <li>我是第四</li>
    <li>我是第五</li>
</ul>

我的JavaScript代码:

//执行环境1-window
(function() {//执行环境-2
    var father = document.getElementById("father");//获取id
    var sub = father.getElementsByTagName("li");//获取li集合
    //下面是用自执行的写法
    for (var i = 0,size = sub.length; i < size; i++) {//通过遍历为每一个li元素都绑定点击事件
        sub[i].onclick = (function(i) {//执行环境-3
            return function() {//执行环境-4
                for (var j = 0; j < size; j++) {
                    sub[j].style.backgroundColor = "white";
                }
                sub[i].style.backgroundColor = "red";
            }
        })(i);
    }
})();

我在执行环境-4的

sub[j].style.backgroundColor = "white";

这一句打断点,我们可以在chrome开发者调试工具看到我们的执行环境,当我点击第一个li元素的时候,我们来看看:

我们看到在chrome的开发者工具看到在当前执行环境的变量有j和this对象,this对象指向当前点击的li元素,当前执行环境的下一个执行环境中的变量有i,以此类推,在scope属性里面我们可以看到我们在当前执行环境下能够调用和修改的变量和函数。

说了那么多,或许我们需要一点练习来增强我们对执行环境这个知识点的理解了,来看下面的一些例题:

1、for循环的情况

var arr=[];
for(var i=0;i<3;i++){
    arr[i]=function(){
        return i;
    };
    log(arr[i]);//这里存的是啥?
}
for(var i=0;i<3;i++){
    log(arr[i]());//会打印啥?
}
log(arr[0]());//?
log(arr[1]());//?
log(arr[2]());//?

你可以先自己判断一下,不过里面可是有很多需要注意的点哦~,来看正确的答案

var arr=[];
for(var i=0;i<3;i++){
    arr[i]=function(){
        return i;
    };
    log(arr[i]);//这里数组存的是一个个函数
}
for(var i=0;i<3;i++){
    log(arr[i]());//0,1,2
}
log(arr[0]());//3
log(arr[1]());//3
log(arr[2]());//3

你猜到结果了吗?我们来解析一下,第一个log会输出一个函数数组,每一个函数返回当前执行环境的i值,在第二个for循环,这里需要注意的是,我们的i在全局执行环境下被重复定义,JavaScript可不会告诉你它被重复定义了哦,所以我们的i被更新,也就是当前执行环境中的i值会从0每次递增1,执行循环就会打印出0,1,2,最后一次循环之后,我们的i变成3,所以在最后打印i值的时候,我们会看到3输出。为什么我们的i不是开始定义函数时候的i值呢,也就是在最后执行函数数组的时候没有输出0,1,2呢,这是因为,我们的作用域链的机制限定闭包只能取得包含函数中任何变量的最后一个值,这也很容易理解,当我们在包含执行环境下创建一个新函数也就是新执行环境,我们将新执行环境推进栈,控制权交给新执行环境,所以包含执行环境下的状态此时只能是最后一次修改的值。

要想输出我们的预期可以这样写:

var arr=[];
for(var i=0;i<3;i++){
    arr[i]=(function(num){
        return num;
    })(i);
}
for(var i=0;i<3;i++){
    log(arr[i]);//0,1,2
}
log(arr[0]);//0
log(arr[1]);//1
log(arr[2]);//2

2、自执行函数

分析一下下面六段代码分别输出什么

var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
            return function(){
                return this.name;
            }
        }
    };
    var female=new Person();
    var myName=female.getName()();
    log(myName);//这里会输出什么?
})();
var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
                return this.name;
        };
    }
    var female=new Person();
    var myName=female.getName();
    log(myName);//输出什么
})();
var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
            return (function(that){
                return that.name;
            })(this);
        };
    }
    var female=new Person();
    var myName=female.getName();
    log(myName);//输出什么
})();
var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
            return function(){
                return this.name;
            }.bind(this);
        };
    }
    var female=new Person();
    var myName=female.getName()();
    log(myName);//输出什么
})();
var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
            return function(){
                return this.name;
            }.call(this);
        };
    }
    var female=new Person();
    var myName=female.getName();
    log(myName);//输出什么
})();
var name="项脊轩";
(function(){
    function Person(){
        this.name="林语",
        this.getName=function(){
            return function(){
                return this.name;
            }.apply(this);
        };
    }
    var female=new Person();
    var myName=female.getName();
    log(myName);//输出什么
})();

好,我们的答案就是除了第一个代码输出是“项脊轩”,其他都是“林语”,后面四个代码向我们展示了如何绑定到当前对象,读者可以自己研究体会一下。



时间: 2024-10-19 11:19:08

JavaScript-执行环境的相关文章

JavaScript 执行环境与作用域

前面我说到过,执行环境是js中最为重要的一个概念.执行环境定义了变量和函数有权访问的其他数据,决定了它们各自的行为. 在JavaScript中,每一个函数都表示为一个对象,更确切地说,是Function对象的一个实例.Function对象与其他的对象一样,都拥有可以编程访问的属性,和一系列不能通过代码访问而仅提供了JavaScript引擎存取的内部属性.譬如[[Call]]属性,表示这个对象可以被执行,其中有一个内部属性是[[Scope]],由ECMA-262标准第三版定义. 内部属性[[Sco

JavaScript执行环境

执行环境(Execution Context,也称为"执行上下文")是JavaScript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其它数据,决定了各自的行为.当JavaScript代码执行的时候,会进入不同的执行环境,这些不同的执行环境就构成了执行环境栈. JavaScript中主要存在三种执行环境: 全局执行环境 JavaScript代码执行的默认环境.通常被默认为window对象,所有的全局变量和函数都作为window对象的属性和方法存在.当执行环境中的代码执行完毕

JavaScript 执行环境及作用域

在JavaScript高级程序设计中,执行环境的定义是:定义了变量或函数有权访问的其他数据,决定了它们各自的行为. 每个执行环境都有一个与之关联的变量对象,环境中定义了所有变量和函数都保存在这个对象中. 其实执行环境就是JavaScript中的作用域 每个函数都有自己的执行环境.当执行流进入一个函数时,函数的环境就会被推入一个环境栈中.而且在函数执行完之后,栈将环境推出,把控制权返回之前的执行环境. 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中任何变量和函数.这些环境

javascript 执行环境,变量对象,作用域链

前言 这几天在看<javascript高级程序设计>,看到执行环境和作用域链的时候,就有些模糊了.书中还是讲的不够具体. 通过上网查资料,特来总结,以备回顾和修正. 要讲的依次为: EC(执行环境或者执行上下文,Execution Context) ECS(执行环境栈Execution Context Stack) VO(变量对象,Variable Object)|AO(活动对象,Active Object) scope chain(作用域链)和[[scope]]属性 EC 每当控制器到达EC

DOM笔记(八):JavaScript执行环境和垃圾收集

一.执行环境 在有关于JavaScript对象或者this的指向问题时,脱离不了的另外一个概念就是执行环境,即上下文环境.执行环境在JavaScript是一个很重要的概念,因为它定义了变量或函数有权访问的其它数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,在该环境中定义的所有变量和函数都保存在这个对象中. 全局环境时最外围的一个执行环境.在Web浏览器中,全局环境被认为是Window对象(后续笔记中会讨论),因此所有的全局变量和函数都是作为window对象的属性或者方法创建的

第六章 javaScript执行环境和作用域

这个只是点对于初学者其实大概了解就可以,但是要研究明白javaScript的机制,就是非常必要的,这只是我的一些记录,大家参考即可,如有错误请指出. 执行环境的概念是javaScript一个虚拟的概念,如何定义它呢?它的作用又是什么呢?它是怎么组成的呢? 大家都比较认可的说法:执行环境又称为执行上下文,从实际的表现来看,可以把它理解为由“对象”组成的一个堆栈.既然是堆栈,就是先入后出了. 组成堆栈的对象是什么对象?我没有找到确切的定义,基于我自己的理解,这个对象是一个自定义对象,里边包含有变量.

Javascript执行环境、作用域链

一.执行环境 执行环境(也叫做执行上下文,Execution Context)是Javascript中最为重要的一个概念.执行环境定义了变量或函数有权访问其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象,执行环境中定义的所有变量和函数都保存在这个对象中.虽然我们编写的代码无法访问这个对象,但解析器在处理时会在后台使用它. 全局执行环境是最外围的一个执行环境.根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样.在web浏览器中,全局执行环境被认为是wi

JavaScript执行环境及作用域

执行环境(executin context)是JS中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中.虽然我们编写的代码无法访问这个对象 ,但解析器在处理数据时会在后台使用它. 全局执行环境是最外围的一个执行环境.根据JS实现的宿主环境不同,表示执行环境的对象也不一样.在Web浏览器中,全局执行环境被认为是Window对象,因此所有全局变量和函

【JS】JavaScript中的执行环境与作用域

JavaScript中的执行环境定义了变量或函数有权访问的数据(每个函数都有自己的执行环境),全局执行环境是最外围的执行环境,在浏览器中,全局执行环境就是window对象,所以所有的全局变量和函数都是作为window对象的属性和方法创建的.当某一个执行环境中所有代码执行完成后,该环境就被销毁,保存在其中的变量和函数也将被销毁,全局执行环境在关闭网页或浏览器时才被销毁. 当代码在一个环境中执行时,会创建变量对象的一个作用域链(保证对执行环境有权访问的变量和函数的有序访问),如果环境是函数,将其活动

Javascript 函数及其执行环境和作用域

函数在javascript中可以说是一等公民,也是最有意思的事情,javascript函数其实也是一个对象,是Function类型的实例.因此声明一个函数首先可以使用 Function构造函数: var saySomething = new Function("something","console.log(something)"); saySomething("hello world!"); // 输出hello world! Function