Javascript Context和Scope的进修总结01【转自cnblogs的JKhuang】

前述

在我们进修Javascript过程当中,常常会碰到作用域(Scope)和实行上下文(Context)等观点。个中,实行上下文与this关键字的关联密切。

有面向对象编程履历的列位,关于this关键字再熟习不过了,因而我们很容易地把它和面向对象的编程体式格局联络在一起,它指向应用组织器新建立出来的对象;在ECMAScript中,也支撑this,但是, 正如人人所熟知的,this不仅仅只用来示意建立出来的对象。

在接下来的博文我们讲引见Javascript的作用域和实行上下文,以及它们的异同的地方。

正文

实行环境(Execution context)也称为“环境”是Javascript中最为主要的一个观点。实行环境定义了变量或函数有权接见的其他数据,决议了它们各自的行动。每一个实行环境都有一个与之关联的变量对象,环境中定义的一切变量和函数都保留在这个对象中。

看到了实行环境的定义有颔首昏了,简而言之“每一个实行环境都有一个与之关联的变量对象”;这里我们有一个疑问就是这个变量对象是如何定义的呢?

接下来,让我们看一下变量对象的定义,详细完成以下:

/**
 * Execution context skeleton.
 */
activeExecutionContext = {
    // variable object.
    VO: {...},
    this: thisValue
};

经由过程上面的伪代码我们晓得对象字面量activeExecutionContext,它包括一个变量对象VO和this属性。

这说明了this与上下文的可实行代码范例有关,其值在进入上下文阶段就肯定了,并且在实行代码阶段是不能转变的(关于this运用能够浏览《Javascript this 的一些进修总结》)。

作用域(Scope)掌握着变量和参数的可见性及生命周期。

简而言之,实行环境是基于对象的,而作用域是基于函数的。

作用域

我们将经由过程一个例子引见作用域的运用,起首,我们定义了一个函数FooA()和FooB,示例代码以下:

/**
 * Defines a function.
 */
var FooA = function(){
    var a = 1;
    var FooB = function(){
        var b = 2;
        console.log(a, b); // outputs: 1, 2
    }
    console.log(a, b); // Error! b is not defined
}
FooA();

在示例中,第二个log输出变量为未定义,这是由于在Javascript中定义在函数内里的参数和变量在函数外部是不可见的,而在一个函数内部任何位置定义的参数和变量,在该函数内部任何地方都是可见的。

实行环境

起首,我们定义了对象字面量o,它包括一个属性x和要领m(),示例代码以下:

/**
 * Defines a literal object.
 * @type {Object}
 */
var o = {
    x:23,
    m: function(){
        var x = 1;
        console.log(x, this.x); // outputs 1, 23
    }
}
o.m();

示例中的两个变量和属性x都能被接见,但它们被接见的体式格局是判然不同,在log中接见第一个x是经由过程作用域体式格局接见了当地变量x,而this.x是经由过程实行上下文体式格局接见对象o的属性x,因而输出值也不尽相同。

上下文题目

接下来,我们修正一下前面的例子,在要领m()中增加一个函数f(),示例代码以下:

/**
 * Defines a literal object.
 * @type {Object}
 */
var o = {
    x:23,
    m: function(){
        var x = 1;
        var f = function(){
            console.log(x, this.x); // outputs 1, undefined
        }
        f();
    }
}
o.m();

上面,我们经由过程挪用要领m()来输出x的值,由于要领m()的详细完成是经由过程挪用函数f()来完成。

当我们挪用对象o的要领m()时,发明this.x是未定义的。

这究竟是什么原因呢?回想前面的例子,由于要领m()猎取了对象o的上下文,所以this是指向对象o的,岂非是函数f()没有猎取对象o的上下文,因而它不清晰this指向哪一个对象?

起首让我们回忆一下函数和要领以及属性和变量的区分:要领和对象关联,如:object.myMethod = function() {},而函数非对象关联:var myFunc = function {};一样属性也是对象关联的,如:object.myProperty = 23,而变量:var myProperty = 23。

由于我们提到上下文是基于对象的,所以函数f()不能猎取对象o的实行上下文。

我们是不是能够让函数f()猎取对象o的实行上下文呢?我们细致地想一下,既然函数f()不清晰this指向的对象,那末能够直接挪用对象的属性就OK了。

/**
 * Fixs broken context issue.
 * @type {Object}
 */
var o = {
    x:23,
    m: function(){
        var x = 1;
        var f = function(){
            console.log(x, o.x); // outputs 1, 23
        }
        f();
    }
}
o.m();

我们在函数f()中直接挪用对象o的属性x,如许函数f()就无需猎取实行上下文直接挪用对象的属性了。

如今,我们又碰到一个新的题目了,假如对象不是o而是p,那末我们就须要修正函数f()中的对象了,更严峻的状况就是我们没有办法肯定详细是哪一个对象,示例代码以下:

/**
 * Defines a literal object.
 * @constructor
 */
var C = function(){}
C.prototype = {
    x:23,
    m: function(){
        var x = 1;
        var f = function(){
            console.log(x, this.x); // outputs 1, undefined
        }
        f();
    }
}
var instance1 = new C();
instance1.m();

上下文实例题目

上面,我们定义了函数C和它的原型对象,而且我们能够经由过程new体式格局建立C对象实例instance1,根据前面的要领处理Broken Context题目,详细完成以下:

/**
 * Defines a literal object.
 * @constructor
 */
var C = function(){}
C.prototype = {
    x:23,
    m: function(){
        var x = 1;
        var f = function(){
            console.log(x, instance1.x); // outputs 1, undefined
        }
        f();
    }
}
var instance1 = new C();
instance1.m();

假如我们在建立一个C的对象实例instance2,那末我们就不能指定函数f()中的对象了。

实在,this是对象实例的笼统,当实例有多个以至成千上百个的时刻,我们须要经由过程this援用这些对象实例。

因而,指定对象要领不能有用处理Broken Context题目,我们照样须要运用this来援用对象,前面我们讲到由于函数f()没有猎取对象o的实行上下文,因而它不清晰this指向哪一个对象,所以输出this.x未定义,那末我们是不是能够让函数f()猎取对象的实行上下文。

跨作用域的上下文

我们想一想既然要领是基于对象的,而且能够猎取对象的实行上下文,那末我们直接把f()定义为要领好了。

如今,我们在C对象原型中定义要领f(),示例代码以下:

/**
 * Defines a literal object.
 * @constructor
 */
var C = function(){}

C.prototype = {
    x:10,
    m: function(){
        var x = 1;
        this.f();
    },
    f: function(){
        console.log(x, this.x); // Reference ERROR!!
    }
}
var instance1 = new C();
instance1.m();

好啦,我们在C对象原型中定义要领f(),那末要领f()就能够猎取对象的实行上下文。

如今,我们在Firefox运转以上代码,效果输出Reference ERROR,这究竟是什么原因呢?我们想了一下题目出于变量x中,由于要领f()不能猎取要领m()的作用域,所以变量x不在要领f()中。

    原文作者:dhonor
    原文地址: https://segmentfault.com/a/1190000008145258
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞