javascript执行原理

执行环境

当执行流执行到函数时会创建一个执行环境,这个执行环境包含了函数内部 语句可以访问的所有变量和函数,当代码执行完时,销毁执行环境。所以一般情 况下,局部变量在函数执行完时会被销毁。

作用域、调用对象

很多人认为作用域是在函数执行时创建的,这是有偏差的理解!

作用域分词法作用域和动态作用域:

  •  词法作用域是在函数定义的时候创建的,作用域的本质是创建它的外层函数的调用对象组成的对象链,函数内部属性[[scope]]指向此作用域。
  •  当调用函数时,会创建一个调用对象(有些地方称活动对象),这个调用对象保存了函数参数和局部变量。将此调用对象推入词法作用域的前端,因此执行时作用域发生了变化,称为动态作用域。

实质上作用域只有一个,都是内部属性[[scope]],词法作用域和动态作用域是时间上的不同造成的划分。作用域链是一条对象链,函数自己的活动对象,接着是父函数的活动对象,接着是祖父函数的活动对象。。。。 函数执行时,是沿着作用域链去寻找标识符的值的,先从自己的活动对象开始。 with、catch 会改变动态作用域,将with的对象和catch的对象压入作用域链前端。

下面出个例子看你是否对作用域链理解到位了:

var obj = {a:1,b:2};
var fn = function(){
     var c=3;
     var a = 5;
     console.log(a);   //a等于多少?
     with(obj){
         a=6;                        
         return function(){return a+c;};
     }
}(); 
fn();     //结果是多少?

闭包  

啥是闭包?

官方:所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。

民间:内部函数拥有外部函数的环境。

通俗的就是内部函数可以访问外部函数的变量。

形成机理:作用域链。

内存及变量查找效率

当有闭包,且内部函数赋给了外部变量引用时,要特别注意内存 。没有赋给外部变量时,代码执行完后执行环境销毁,不会有变量贮存内存。但赋给了外部变量时,闭包的词法作用域链会持有外层函数的活动对象,使得外部的变量不会回收。为了有效回收应该将变量设为null,断开引用。

var fn = function(){
    var div = document.getElementById("div");
    return function(){};    
};  //div不会销毁

根据作用域链的原理,处于作用链前端的变量会更快找到,所以尽量用局部变量。

1 var a,b,c;
2 var fn = function(){
3     var d,e,f;
4     return function(){ 
5         var h,j,k; 
6          return typeof nothing; //nothing这个变量查找了整条作用域链,直到查询到window中这个变量,才返回"undefined".
7     };    
8 };

this

this跟arguments一样是函数执行时,活动对象的一部分。this是动态的,函数执行时候绑定。

大概有这几种情况:

(1) 函数,this==window

var fn = function(){console.log(this==window);}; //true

fn(); //不管函数fn在任何地方定义,是顶层函数,还是嵌套 ,this都等于window

(2) 方法,this==obj

var obj = {};

obj.fn = function(){console.log(this==obj);}; //true

obj.fn();

(3)setTimeout setInterval,this==window

var obj = {};

var fn = function(){console.log(this==obj);};

setTimeout(fn,1000); //?

obj.fn = fn;

setTimeout(obj.fn,1000); //?

(4)call,apply将函数or方法绑定给了对象,this==obj

var obj = {};

var fn = function(){console.log(this==obj);}; //true

fn();

fn.call(obj);

(5)事件处理程序

DOM0

btn.onclick = function(){console.log(this==btn);}; //true

DOM2

btn.addEventListener("click",function(){
     console.log(this==btn);        //true
},false);

IE

btn.attachEvent("onclick",function(){
      console.log(window==btn);   //true
});
原文地址:https://www.cnblogs.com/xuntu/p/3618896.html