xml地图|网站地图|网站标签 [设为首页] [加入收藏]

JavaScript中的this关键字

时间:2020-01-04 21:40来源:计算机
JavaScript中的this关键字 JavaScript中的this关键字 JavaScript函数中的关键字this并不指其本身(Itself),举例说明: function foo(num) { console.log( foo: + num ); // keep track of how many times `foo` is called t

JavaScript中的this关键字

JavaScript中的this关键字

JavaScript函数中的关键字this并不指其本身(Itself),举例说明:

function foo(num) {
    console.log( foo:  + num );

    // keep track of how many times `foo` is called
    this.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
    if (i > 5) {
        foo( i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 0 

上例中尽管foo()执行了4次,但是foo.count依然为0,说明this指代的并不是foo函数自身。那么我们执行的count++到底是给什么值在增加呢?实际上我们创建了一个全局变量count,即window下的一个变量,其初始值为NaN,即使其被增加了4次,其值依然为NaN。

若上述示例改为下面就很容易理解:

function foo(num) {
    console.log( foo:  + num );

    // keep track of how many times `foo` is called
    data.count++;
}

var data = {
    count: 0
};

var i;

for (i=0; i<10; i++) {
    if (i > 5) {
        foo( i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( data.count ); // 4

但是这里,我们并没有用到this关键字,我们只是选择性地回避了this,采用了另一种方式-Lexical scope来完成的。

如果我们要在函数内部引用其自身时,我们只能采用lexical identifier (variable)来指向其自身,如下:

function foo() {
    foo.count = 4; // `foo` refers to itself
}

此种方式对于有函数名的函数有效,但是对于匿名函数就无能为力了,比如下面:

setTimeout( function(){
    // anonymous function (no name), cannot
    // refer to itself
}, 10 );

对此我们无能为力,不过有一个并不建议使用(目前已废弃的方式)的方式来引用函数自身:arguments.callee,实际上我们最好的方式就是在需要引用函数自身时不要使用匿名函数,这样就避免了上述问题的出现。

所以我们最开始时如果我们要引用自身函数时,采用其自身的函数名(identifier )即可:

function foo(num) {
    console.log( foo:  + num );

    // keep track of how many times `foo` is called
    foo.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
    if (i > 5) {
        foo( i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 4

上例中我们似乎还是回避了this关键字,只不过上例中我们要引用函数自身,不能使用this关键字。

如果我们一定要使用this关键字来指代函数自身时,我们可以这样做:

function foo(num) {
    console.log( foo:  + num );

    // keep track of how many times `foo` is called
    // Note: `this` IS actually `foo` now, based on
    // how `foo` is called (see below)
    this.count++;
}

foo.count = 0;

var i;

for (i=0; i<10; i++) {
    if (i > 5) {
        // using `call(..)`, we ensure the `this`
        // points at the function object (`foo`) itself
        foo.call( foo, i );
    }
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9

// how many times was `foo` called?
console.log( foo.count ); // 4

另一个对于this的误解是指:this指的是函数的lexical scope,You Dont Know JS 中关于this有这样的一段话:

To be clear, this does not, in any way, refer to a function’s lexical scope. It is true that internally, scope is kind of like an object with properties for each of the available identifiers. But the scope “object” is not accessible to JavaScript code. It’s an inner part of the Engine’s implementation.

请看下例:

function foo() {
    var a = 2;
    this.bar();
}

function bar() {
    console.log( this.a );
}

foo(); //undefined

上述代码试图通过this在foo()和bar()的lexical scopes中建立桥梁,所以通过bar()来获取foo()的inner scope的变量a,这样的桥梁实际上并不存在。

那么this机制到底是怎样的呢?其实,this是在运行时绑定的(runtime binding),而不是创建时绑定(author-time binding),即函数在调用时是基于其上下文来绑定的。

You Dont Know JS 中关于this机制有这样的一段话:

‘This’ is not an author-time binding but a runtime binding. It is contextual based on the conditions of the function’s invocation. this binding has nothing to do with where a function is declared, but has instead everything to do with the manner in which the function is called.

When a function is invoked, an activation record, otherwise known as an execution context, is created. This record contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc. One of the properties of this record is the this reference which will be used for the duration of that function’s execution.

上述提到,this是在函数调用时基于其Call-site来绑定的,那么什么是Call-site呢

call-site: the location in code where a function is called (not where it’s declared).

那么如何确定函数的call-site呢,

go locate where a function is called from

但是,确定函数的call-site并不容易,因此我们换一种思路,来寻找函数的call-stack:

the stack of functions that have been called to get us to the current moment in execution

下面我们来通过例子来说明call-site和call-stack的关系:

function baz() {
    // call-stack is: `baz`
    // so, our call-site is in the global scope

    console.log( baz );
    bar(); // <-- call-site for `bar`
}

function bar() {
    // call-stack is: `baz` -> `bar`
    // so, our call-site is in `baz`

    console.log( bar );
    foo(); // <-- call-site for `foo`
}

function foo() {
    // call-stack is: `baz` -> `bar` -> `foo`
    // so, our call-site is in `bar`

    console.log( foo );
}

baz(); // <-- call-site for `baz`

我们可以通过浏览器的dev Tool的debugger来调试查看函数的call-stack。

在我们清楚 call-site之后,我们来看this绑定的四条准则:

1. Default Binding

这条是最常见的绑定规则,也就是说this指向global object,请看例子:

function foo() {
    console.log( this.a );
}

var a = 2;

foo(); // 2

如果在strict mode下,this指向undefined:

function foo() {
    use strict;

    console.log( this.a );
}

var a = 2;

foo(); // TypeError: `this` is `undefined`

其中,一个细节要注意,如果foo()不是在strict mode下,其this仍指向global object:

function foo() {
    console.log( this.a );
}

var a = 2;

(function(){
    use strict;

    foo(); // 2
})();

 

JavaScript中的this关键字 JavaScript函数中的关键字this并不指其本身(Itself),举例说明: function foo(num) { console.log( foo...

编辑:计算机 本文来源:JavaScript中的this关键字

关键词:

  • 上一篇:没有了
  • 下一篇:没有了