javascript之作用域和this

252 阅读2分钟

1.作用域

首先比较下面两段代码:

// A--------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

// B---------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

运行可得,A和B两端代码输出返回的都是local scope。

JavaScript采用的是词法作用域,函数的作用域基于函数创建的位置。

当查找变量时,会从当前函数上下文的变量对象中查找,如果没找到,就会从父级的变量对象中查找,一直找到全局对象。

这样由多个执行上下文的变量对象构成的链表就叫作用域链

2.执行上下文

JavaScript 引擎并非一行一行地分析和执行程序,而是一段一段地分析执行,创建了执行上下文栈来管理执行上下文。

当执行一个函数的时候,会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕时,会将函数的执行上下文从栈中弹出。

上面两段代码的区别是执行上下文栈的变化不一样。

// A--------------------------
push(checkscope) //创建checkscope的执行上下文
push(f)  //创建f的执行上下文
pop() //f执行完毕
pop() //checkscope执行完毕

// B---------------------------
push(checkscope) //创建checkscope的执行上下文
pop() //checkscope执行完毕
push(f)  //创建f的执行上下文
pop() //f执行完毕

再继续刨根问底,研究每个执行上下文的过程,可以参考《一道js面试题引发的思考》

3.this

this是指向函数运行时所在的环境。

var obj = {
   foo:function(){
       console.log(this.bar);
       bar:1
   }
}
var foo=obj.foo;
var bar=2;
obj.foo(); // 1
foo(); // 2

obj.foo():是通过obj找到foo,foo运行在obj环境里,this指向obj,因此返回当前函数上下文的变量bar:1

foo():因为var foo=obj.foo,foo直接指向函数本身,所以foo运行在全局环境,this指向全局环境,因此返回全局变量bar:2

那么函数的运行环境是怎样决定的?跟内存的数据结构有关,详细参考JavaScript 的 this 原理

  • 直接调用:this指向全局变量

  • call()、apply(),bind():this指向被绑定的对象,即第一个参数

  • 箭头函数:this都指向外层,函数定义时所在的环境,而不是执行时的环境

  • 作为对象中的一个方法:this指向调用函数的对象

  • 作为构造函数:this指向被绑定的构造函数的新对象

  • 作为DOM事件处理函数:this指向触发事件的DOM节点

总结判断顺序:

  1. 由new调用:绑定到新创建的对象

  2. 由call,apply,bind调用:绑定到指定的对象

  3. 由上下文对象调用:绑定到上下文对象

  4. 默认:全局对象

一道面试题:segmentfault.com/a/119000001…