Javascript中的范围和上下文使用的简要概述

范围(范围)和语境(上下文)在Javascript语言的独特性,这部分是由于他们所带来的灵活性,每个函数都有不同的背景和变量的范围。这些概念是在Javascript中一些强大的设计模式的支持。然而,这也带来了很大的困惑开发商。以下是在Javascript中的语境和范围差异全面的启示,以及如何使用各种设计模式。

语境与范围

首先要澄清的是,上下文和范围是不同的概念,多年来,我注意到许多开发人员常常混淆这两个术语,而错误的描述另一个术语,说实话,这些术语变得非常混乱。

每个函数调用的范围和它的相关背景。从根本上讲,范围是基于功能(功能型)和语境是基于一个对象(对象)。换句话说,活动的范围是在每个函数调用的变量的访问有关,和每个调用上下文无关。都是关键字的值,一个对象的引用,调用当前执行的代码。

变量范围

变量可以在本地或全球范围的界定,导致运行时变量来自不同范围的访问。全局变量必须在函数的函数声明,它存在在运作,并可以在任何范围修改。局部变量只在函数体中定义的,和每一个函数都有一个不同的范围。本课题是在调用的值,和值的操作价值的评价,和值超出范围。

目前,Javascript不支持块级范围。块级范围的方式定义变量的语句块,如if语句,switch语句,循环语句,这意味着变量不能在语句块的访问。目前任何变量定义在一个语句块可以外块访问。然而,这种情况即将改变,并且让关键词已正式添加到6规范。它可以用作一个var关键字声明一个局部变量作为一个块级范围的替代品。

这个上下文

上下文通常取决于函数的调用方式。当函数的函数被称为对象时,它被设置为调用方法的对象:

复制代码代码如下所示:
var对象{ { {
函数(){
警报(此=对象);
}
};

(object)

当调用一个函数时,同样的原理也适用于新操作符创建一个对象的实例,当用这种方式调用时,这个值将被设置为新创建的实例:
复制代码代码如下所示:
函数(){
警戒(此);
}

(富)窗口
新(富)

当调用未绑定函数时,将默认设置为全局上下文(全局上下文)或窗口对象(如果在浏览器中)。但是,如果该函数在严格模式下执行(使用严格),则默认情况下该值将被设置为未定义。
执行上下文和动作链

Javascript是一种单线程语言,它在浏览器中同时表示一件事,当Javascript解释器初始化执行代码时,它首先默认为全局上下文。每次调用函数都会创建一个新的执行上下文。

这里经常发生混乱。长期的执行上下文(执行上下文)这里指的范围,而不是之前讨论的背景下,这是一个糟糕的名字,但长期由ECMAscript规范定义,但要遵守。

每一次新的执行上下文被创建,它被添加到作用域链的顶端,也是执行或调用堆栈。浏览器总是运行在作用域链的顶部执行上下文的顶部。一旦完成,它(当前执行上下文)将从堆栈的顶部去掉,将返回到执行上下文在控制返回。例如:
复制代码代码如下所示:
函数第一(){
第二();
函数第二(){
第三();
函数第三(){
第四();
函数第四(){
做某事
}
}
}
}
第一();

运行上面的代码会导致嵌套功能下降从上到下直到第四功能实现和作用域链是从上到下:第四,第三,二,一,全球。第四功能可以访问一个全局变量和变量定义在第一,第二,和第三的功能,正如访问自己的变量。一旦执行第四的功能,第四晕上下文将从作用域链上执行删除将返回到第三功能。这个过程继续下去,直到所有的代码已经被执行。

不同的执行上下文之间的变量命名冲突是通过将范围链从本地扩展到全局来解决的,这意味着同名的本地变量在操作链中具有更高的优先级。

在一个简单的方法,你的每一次尝试访问一个函数的上下文变量,查找过程总是从自己的可变对象。如果你找不到变量在变量对象中找到,继续搜索的范围链。它试图爬范围链来检查每个执行上下文可变对象发现名称的变量匹配值。

关闭

当嵌套函数外定义访问(范围),它可以在外部函数返回执行,并关闭在这个时候形成的。它(关闭)保持(在内部功能)在外部函数访问局部变量、参数和函数声明。封装允许我们隐藏和保护的执行上下文,从外部的范围,同时通过接口暴露的公共接口和进一步操作。一个简单的例子如下:
复制代码代码如下所示:
函数(){
局部变量var =担保的非盈利;
返回函数条(){
返回本地;
}
}

无功getlocalvariable = foo();
getlocalvariable(私人) / /变量

最流行的闭包是一个众所周知的模块模型,它允许您模拟公共、私有和特权成员:
复制代码代码如下所示:
var模块=(函数(){())
var = 'foo的私有财产;

功能privatemethod(args){
做某事
}

返回{

公共财产:

publicmethod:功能(args){
做某事
},

privilegedmethod:功能(args){
privatemethod(args);
}
}
});

该模块实际上是有点类似于一个单一的情况下,加上最后一对圆括号,当翻译工作完成(立即执行的功能),关闭执行唯一的外部可用的成员在返回对象的常用方法和属性(如模块。publicmethod)。然而,所有私有属性和方法将在整个项目生命周期的存在,因为(Bi Bao)保护的执行上下文,和变量的相互作用是通过一个共同的方式。

另一种叫封立即调用函数表达的生活立即,这无非是一个自我调用匿名函数在窗口的上下文(自调用匿名函数)。
复制代码代码如下所示:
函数(窗口){

创建一个'foo,B = 'bar;

函数私有(){
做某事
}

窗口。模块{ {

公共:函数(){
做某事
}
};

});

为了保护全局名称空间,这个表达式非常有用。函数体中声明的所有变量都是局部变量,通过闭包保持在整个操作环境中,这种封装源代码的方式非常受程序和框架的欢迎,通常向外部世界暴露一个单一的全局接口。

调用和应用

这两个简单的方法是在所有函数中构建的,允许函数在一个定制上下文中执行。调用函数需要一个参数列表,应用函数允许您将参数作为数组传递:
复制代码代码如下所示:
函数用户(第一,最后,年龄){
做某事
}
user.call(窗口,约翰,'doe ',30);
User.apply(窗口,{约翰','doe ',30 });

执行的结果是相同的,在窗口上下文调用用户函数,并提供相同的三个参数。

ECMAscript 5(ES5)介绍了function.prototype.bind方法控制语境,它返回一个新的功能,这是永久绑定的绑定方法的第一个参数,不管如何被调用的函数。它纠正了对功能的情况下通过关闭,以下是不支持的浏览器的解决方案:
复制代码代码如下所示:
如果(!('bind'in函数原型)){
function.prototype.bind =函数(){
var fn =,上下文=论点{ 0 },args = array.prototype.slice.call(参数1);
返回函数(){
返回fn.apply(上下文,args);
}
}
}

它往往是在上下文中使用的损失:面向对象和事件处理,这是必要的因为节点的addEventListener方法始终保持对事件处理的约束节点的函数执行的上下文,这是非常重要的。然而,如果你使用先进的面向对象技术和需要保持回调函数的背景是该方法的一个实例,你必须手动调整的背景下,这是通过结合带来方便:
复制代码代码如下所示:
函数的MyClass(){
this.element = document.createelement('div);
This.element.addEventListener(听到咔哒声,this.onclick.bind(这),假);
}

myclass.prototype.onclick =功能(e){
做某事
};

当您回顾绑定函数的源代码时,您可能会注意到下面的行比较简单,并调用数组的方法:
复制代码代码如下所示:
array.prototype.slice.call(参数1);

有趣的是,我们需要注意的参数对象其实不是一个数组,但它通常被描述为一个对象数组(阵列),这是很多返回的结果列表(document.getelementsbytagname()方法),它们含有长度属性和值可以被索引,但他们仍然不是数组,因为他们不支持本地阵列的方法,如切片推。然而,因为他们有类似的行为,一个数组,数组的方法可以被劫持。如果你想这样做,在一类数组中执行一个阵列的方法,参照上面的例子。

这种调用其他对象方法的技术也应用于面向对象,当在Javascript(类继承)中模仿经典继承时:
复制代码代码如下所示:
myclass.prototype.init =函数(){
调用父类的init方法 / MyClass实例的上下文
MySuperClass.prototype.init.apply(这个参数);
}

我们可以通过调用父类的方法复制这个强大的设计模式(mysuperclass)的子类的实例(MyClass)。

结论

理解这些概念,在你开始学习先进的设计模式是非常重要的,因为范围和语境的重要作用在现代Javascript。语境和范围发挥着重要的作用,无论我们谈论的封锁,面向对象,继承或多种原生实现。如果你的目标是掌握Javascript语言了解它的组成、范围和上下文应该是你的起点。

译者补充

作者实现的绑定函数是不完整的,绑定返回的函数不能传递参数,下面的代码修复这个问题:

复制代码代码如下所示:
如果(!('bind '功能。原型)){
function.prototype.bind =函数(){
var fn =,上下文=论点{ 0 },args = array.prototype.slice.call(参数1);
返回函数(){
返回fn.apply(上下文,args.concat(参数)); / /固定
}
}
}