深入浅析深入浅析JavaScript中的作用域和上下文中的作用域和上下文
javascript中的作用域(scope)和上下文(context)是这门语言的独到之处,这部分归功于他们带来的灵活性。本文
给大家介绍JavaScript中的作用域和上下文,感兴趣的朋友一起学习
javascript中的作用域(scope)和上下文(context)是这门语言的独到之处,这部分归功于他们带来的灵活性。每个函数有不同的
变量上下文和作用域。这些概念是javascript中一些强大的设计模式的后盾。然而这也给开发人员带来很大困惑。下面全面揭
示了javascript中的上下文和作用域的不同,以及各种设计模式如何使用他们。
上下文(上下文(Context)和作用域()和作用域(Scope))
首先需要知道的是,上下文和作用域是两个完全不同的概念。多年来,我发现很多开发者会混淆这两个概念(包括我自己),
错误的将两个概念混淆了。平心而论,这些年来很多术语都被混乱的使用了。
函数的每次调用都有与之紧密相关的作用域和上下文。从根本上来说,作用域是基于函数的,而上下文是基于对象的。 换句
话说,作用域涉及到所被调用函数中的变量访问,并且不同的调用场景是不一样的。上下文始终是this关键字的值, 它是拥有
(控制)当前所执行代码的对象的引用。
变量作用域变量作用域
一个变量可以被定义在局部或者全局作用域中,这建立了在运行时(runtime)期间变量的访问性的不同作用域范围。 任何被
定义的全局变量,意味着它需要在函数体的外部被声明,并且存活于整个运行时(runtime),并且在任何作用域中都可以被
访问到。 在ES6之前,局部变量只能存在于函数体中,并且函数的每次调用它们都拥有不同的作用域范围。 局部变量只能在
其被调用期的作用域范围内被赋值、检索、操纵。
需要注意,在ES6之前,JavaScript不支持块级作用域,这意味着在if语句、switch语句、for循环、while循环中无法支持块级
作用域。 也就是说,ES6之前的JavaScript并不能构建类似于Java中的那样的块级作用域(变量不能在语句块外被访问到)。
但是, 从ES6开始,你可以通过let关键字来定义变量,它修正了var关键字的缺点,能够让你像Java语言那样定义变量,并且
支持块级作用域。看两个例子:
ES6之前,我们使用var关键字定义变量:
function func() {
if (true) {
var tmp = 123;
}
console.log(tmp); // 123
}
之所以能够访问,是因为var关键字声明的变量有一个变量提升的过程。而在ES6场景,推荐使用let关键字定义变量:
function func() {
if (true) {
let tmp = 123;
}
console.log(tmp); // ReferenceError: tmp is not defined
}
这种方式,能够避免很多错误。
什么是什么是this上下文上下文
上下文通常取决于函数是如何被调用的。当一个函数被作为对象中的一个方法被调用的时候,this被设置为调用该方法的对象
上:
var obj = {
foo: function(){
alert(this === obj);
}
};
obj.foo(); // true
这个准则也适用于当调用函数时使用new操作符来创建对象的实例的情况下。在这种情况下,在函数的作用域内部this的值被
设置为新创建的实例:
function foo(){
alert(this);
}
new foo() // foo
foo() // window
当调用一个为绑定函数时,this默认情况下是全局上下文,在浏览器中它指向window对象。需要注意的是,ES5引入了严格模
式的概念, 如果启用了严格模式,此时上下文默认为undefined。