首页 > 编程笔记 > JavaScript笔记 > JS函数

JS this和调用对象

JavaScript 函数的作用域是静态的,但是函数的调用却是动态的。由于函数可以在不同的运行环境内执行,因此 JavaScript 在函数体内定义了 this 关键字,用来获取当前的运行环境。

this 是一个指针型变量,它动态引用当前的运行环境。具体来说,就是调用函数的对象。调用对象是可以访问的 JavaScript 对象,而执行上下文的变量对象是一个不可访问的抽象概念。同时,在一个执行上下文中会存在多个调用函数的对象,但是只有一个变量对象。

示例1

下面示例在全局上下文中声明一个变量 x,初始化值为 1。然后在 obj 对象内定义一个属性 x,初始化值为 2。使用函数 f 检测不同运行环境下 x 值的变化,以此检测 this 指针的引用对象。
var x = 1;  //声明全局变量并初始化
var obj = {
    f : function () {  //定义方法f
        console.log(this.x);  //访问当前运行环境中x的属性值
    },
    x : 2,  //定义属性x,赋值为2
};
//obj环境执行
obj.f();  //2
var f1 = obj.f;
//window环境运行
f1();  //1
在上面代码中,obj.f() 表示在 obj 对象上调用 f 函数,则调用对象为 obj,此时 this 就指向 obj,this.x 就等于 obj.x,即返回结果为 2。若把 obj.f 赋值给变量 f1,然后在全局上下文中调用 f1 函数,则 f 函数体的运行环境在全局上下文中执行,此时 this 就指向 window,this.x 就等于 window.x,即返回结果为 1。

示例2

this 总是指代函数的当前运行环境。针对示例 1 的代码,如果使用下面 3 种方式调用 f 函数,会发现返回值都是 1。
var x = 1;  //声明全局变量并初始化
var obj = {
    f : function () {  //定义方法f
        console.log(this.x);  //访问当前运行环境中x的属性值
    },
    x : 2,  //定义属性x,赋值为2
};
(obj.f = obj.f) ();  //1
(false || obj.f) ();  //1
(obj.f, obj.f) ();  //1
在上面代码中,小括号左侧都是一个表达式,表达式的值都是 obj.f,而在示例 1 中可以看到使用 obj.f() 调用函数 f,返回值是 2。为什么现在换一种表示方法返回值都是 1 呢?

问题的关键是如何正确理解“运行环境”。上面 3 种表达式中,obj.f = obj.f 是赋值表达式,把 obj.f 赋值给 obj.f,obj.f 是一个地址,把地址赋值给 obj.f 属性,表达式的运行环境发生在全局上下文中,所以此时函数 f 内的 this 就指向了全局上下文的调用对象 window。

false || obj.f 是一个逻辑表达式,左侧操作数为 false,则运算右侧操作数,返回 obj.f 的值,即引用地址。由于这个逻辑表达式运算发生在全局作用域内,此时的 f 函数内 this 就指向了全局对象。

obj.f,obj.f 是一个逗号运算表达式,逗号左侧和右侧的 obj.f 都是一个地址,都被运算一次,最后返回第 2 个操作数的值,即返回引用地址。由于这个操作发生在全局作用域内,所以 f 函数内 this 也指向了全局对象。

但是,对于下面形式的调用,不会返回 1,而是返回 2,即 this 指向 obj 对象。因为小括号不是一个运算符,它仅是一个逻辑分隔符,不执行运算,不会产生运行环境。当使用小括号调用函数时,此时发生的运行环境就是 obj 了。
(obj.f) ();  //2

所有教程

优秀文章