文章目录
  1. 1. 函数传递中的this
  2. 2. 构造函数中的this
  3. 3. 闭包中的this
  4. 4. HTML事件绑定中的this

在JavaScript中,this是函数中的一个特殊对象,它表示的是函数执行环境所在的环境对象。函数执行的时候会生成一个执行环境,这个执行环境又会包含在某个对象中,如:直接在脚本中声明一个函数再执行,那么这个环境对象就是window;在一个对象中执行函数,这个环境对象就是当前执行函数所在的对象。下面列出几种常见的陷阱:

函数传递中的this

var name = "The Window";
    var object = {
        name : "My Object",
        getName: function(){
        return this.name;
    }
};
(object.getName = object.getName)(); //"The Window"

打印出来的结果是”The Window”,也许有点奇怪,但是按照上面的思路来分析,其实很简单,object.getName引用传递给本身,然后匿名函数在window环境中执行,上面的代码可以转换为:

var name = "The Window";
    var object = {
        name : "My Object",
        getName: function(){
        return this.name;
    }
};

object.getName = object.getName;
var temp = object.getName;
temp();//输出The Window

这样转换之后就很清楚的看到,最后匿名函数的执行环境其实包含在window对象中的,所以输出的是The Window。

构造函数中的this

var name = 'global';
function Person() {
    var name = 'local';
    console.log(this.name);
}
Person();//输出global
new Person();//输出undefined

如代码所示,第一次执行表示正常的函数执行,输出global没问题,第二个就纳闷了,怎么是undefined?new Person()是构造函数方式创建对象,有点特殊性,可以参考前面的《理解JavaScript原型模式》,可以这样理解,当执行new Person时会分配一个Person实例的内存空间,加上括号就执行Person构造函数,这时Person构造函数所属的对象就是新建的实例对象,而这个实例对象里面什么都没有,所以输出undefined了,如果想要输出属性值,就得给实例赋值,如:this.name=’local’赋值之后,创建的实例就可以输出local了。

闭包中的this

同样是上面的例子,直接把getName函数的返回值改成一个匿名函数:

var name = "The Window";
var object = {
    name : "My Object",
    getName: function(){
        return function(innerName) {
            console.log(this.name);//输出The Window
        };
    }
};
object.getName()('inner');

如果不小心,单从object去分析就很容易出错,object.getName()(‘inner’)这段代码其实也是window对象中的一个匿名函数的执行,等价于:

var temp = object.getName();//获得返回的匿名函数
temp('inner');

这样可以看到temp就是一个闭包,执行环境是在window对象中执行,所以this就是当前window全局变量了。

有时候在命名自己的私有空间时,也常常会用到闭包,下面再来一个闭包场景下的this:

var name='global';
var Global = (function() {
    var name = 'local';

    var getName = function() {
        console.log(this.name);
    }

    return {
        name : 'obj',
        objGetName : getName
    }
})();
Global.objGetName();//输出obj

上面代码可以看出有3个name,看上去输出哪个name有点晕乎,前面说了只要记住函数执行环境所在的对象,不管嵌套多少个函数,其实分析起来都很简单的。这里我们看到会最先执行匿名函数,然后把返回的一个匿名对象赋值给Global对象,在返回对象中getName赋值给了objGetName,执行objGetName函数所在对象是Global,里面的this对象其实就变成了返回的匿名对象了,所以this.name表示的就是匿名对象中的name了。

HTML事件绑定中的this

HTML元素其实都是一个对象,里面的各种事件就是函数,事件里面执行函数就相当于一个闭包,拿个例子来说:

<input type="text" id="nameInput" onclick="this.value = 2"/>

var nameInput = document.getElementById('nameInput');
console.log(nameInput.onclick);//onclick属性是一个函数

执行onclick事件时,执行函数环境就包含在input标签对象中了,所以事件中的this表示的就是input对象了。
如果onclick事件中嵌套一个函数,那这个函数中的this还是input对象么?

<input type="text" id="nameInput" onclick="doAction()"/><br>

function doAction() {
    var nameInput = document.getElementById('nameInput');
    console.log(nameInput.onclick);//onclick属性是一个函数
    console.log(this);//输出window对象
    this.value = Math.random();
}

意料之中输出的是window对象,最简单粗暴的理解方式就是最后执行doAction函数所在对象是在window对象中,所以不用管onclick到底所属对象。可以换一种写法:

function doAction() {
    console.log(this);//输出window对象
}

function onclick() {
    doAction();
}

var nameInput = document.getElementById('nameInput');
nameInput.onclick();

这样就可以更直观的看到其实就是一般的函数之间的调用了。如果想用onclick所在的html元素对象,就执行函数里面添加一个this参数就可以了,如:

<input type="text" id="nameInput" onclick="doAction(this)"/><br>
文章目录
  1. 1. 函数传递中的this
  2. 2. 构造函数中的this
  3. 3. 闭包中的this
  4. 4. HTML事件绑定中的this