执行环境、作用域(链)、this、垃圾回收、闭包

一、执行环境

        当执行流进入一个新函数时,函数的环境就会被推入一个环境栈中,当函数执行完毕,该环境从栈顶弹出。栈顶永远是当前执行环境,栈底为全局环境。

        每个执行环境都有一个与之相关的变量对象,全局环境下是window,环境中定义的所有的变量和函数都保存在这个对象中,变量对象在环境创建过程中初始化,这时候由于var声明的变量以及函数声明存在变量提升,因此代码还没有执行,变量对象中就已经存在这些变量了,但此时var声明的变量取值为undefined。当代码在环境中执行时,会创建变量对象的一个作用域链,执行环境为函数时,变量对象为活动对象。

        唯一的全局执行环境,局部执行环境个数没有限制,每次某个函数被调用,就会有个新的执行环境为其创建,即使是多次调用自身函数。

二、作用域链

        作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,作用域链前端是当前执行代码所在环境的变量对象,下一个变量对象来自包含环境,以此类推,末端为全局环境下的变量对象。原理是函数内部属性[[Scope]](指针),函数在定义时就已经存在[[Scope]]指针,指向父级环境,当函数执行环境被创建时,该环境的作用域链初始化为函数的内置属性[[Scope]]所包含的对象,即当前环境和之前的[[Scope]]的和

三、this

        this是在执行环境创建时绑定的。

        1、在全局环境中,this为window/global

        2、函数中的this

             JavaScript引用类型的值可以看做一个对象,包括base(属性拥有者)属性和propertyName(属性值)属性,js处理引用类型值的两种情况:①标识符 ②属性访问器。

        标识符:常见如变量、函数名,解析的过程就是找到该变量属于哪个变量对象,即base的值               

var foo = 5;
function bar(){};
处理为:
var fooReference = {
  base: global/window,
  propertyName: 'foo'
}; 
var barReference = {
  base: global/window,
  propertyName: 'bar'
};

        属性访问器:点(.)语法或[]语法

var foo = {
  bar : function(){}
}
foo.bar();
foo['bar']();
处理为:
var fooBarReference = {
  base: foo,
  propertyName: 'bar'
};

        在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。

         当函数直接被调用,即作为标识符引用类型,this为全局对象window/global。属性访问器方式访问,this为调用它的对象。特别注意:

var name ="i am from window";
var foo = {
  name : "i am in foo",
  getName : function(){
    alert(this.name);
  }
}
var bar = foo.getName;
bar();//i am from window      //作为标识符引用

foo.getName();//i am in foo     //属性访问器引用

        立即执行函数的()左侧不是引用类型,所以内部this指向全局对象,活动对象内直接调用另外一个含有this的函数,this指向全局。

        3、手动改变this

        Function.prototype.call、Function.prototyope.apply、Function.prototype.bind改变this指向,第一个参数作为this对象,apply第二个参数为数组或类似数组对象,call接受任何参数。bind参数与call相同,非立即执行。   

        4、new一个对象时,发生了什么

        ①创建一个全新的对象

        ②这个新对象会被执行[[Prototype]]连接

        ③这个新对象会绑定到函数调用的this

        ④如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

        使用构造函数调用的时候,this会绑定到new期间创建的对象上

        5、箭头函数中的this

        ①继承于它外面第一个不是箭头函数的函数的this指向

        ②this一旦绑定上下文,就不会被任何代码改变

四、垃圾回收

        找出不再使用的变量,释放占用的内存

        标记清除:所有变量打上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),完成后仍然存在标记的就是要删除的变量了

        引用计数:跟踪记录每个值被引用的次数,当减少为0时就代表无法访问了,将其内存空间收回。存在循环引用(通过属性互相引用)的问题,导致大量内存得不到回收。最简单的方法是手动解除引用,例:a.m=null;

五、闭包

        闭包是函数和声明该函数的词法环境的组合。当函数可以记住并引用所在的词法作用域时,就产生了闭包,闭包能阻止垃圾回收,滥用容易造成内存泄漏。精确来说,不论用何种手段把内部函数传递到所在词法作用域以外,它都会保持对原始定义作用域的引用,无论在何处执行这个函数都会使用闭包,所以,闭包是连接函数内和函数外的桥梁

this部分参考https://www.cnblogs.com/teamobaby/p/3844894.html

猜你喜欢

转载自blog.csdn.net/wwjwy123/article/details/80895129