Introduction 导言

Javascript函数中的this关键字的行为相比其他语言有很多不同。在Javascript的严格模式下和非严格模式下也略有不同。

在大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,在每次函数被调用时this的值也会不同。ES5增加了bind方法,可以在不对函数进行调用的情况下传入this值。

Global context 全局上下文

在全局上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下。

console.log(this.doucment === document)   //true
//In web browsers, the window object is also the global object:
console.log(this === window);   //true

this.a = 37;
console.log(window.a);  //37


在函数内部, this的值取决于函数是如何调用的。Function context 函数上下文

Simple call 直接调用

function f1() {
        return this;
    }
    
f1() === window;  //global object



function f2() {
    "use strict";
    return this
    }
    
f2() === undefined;  //return undefined


在这个例子中,this的值不是由函数调用设定。因为代码不运行在严格模式下,this的值始终是一个对象且默认为全局对象。

在严格模式下,this的值根据执行时的上下文,this所保存的值决定。若为定义,this仍是undefined, 它可能被设置为任何的值,比如null,42或者是 “ I’am not this “。

在第二个例子中,this的值应该是undefined。因为f2被调用时未基于任何对象(e.g.window.f2())。这个功能并未在所有第一次开始支持严格模式的浏览器中都得到广泛支持,在不支持的浏览器中,仍然返回window,比如chrome。

As an object method 作为对象方法

当一个函数作为一个对象的方法被调用,它的this会被设置为调用该方法的对象。
在下面的例子中,当o.f()被调用,function内部的this会绑定到这个object。

var o = {};
o.prop = 37;
o.f = function() {
    return this.prop;
    };
console.log(o.f()); //37



var o = {prop:37};
function independent(){
    return this.prop;
}

o.f = independent;

console.log(o.f());     //logs 37


注意,如何调用或者在何处定义这个函数并不影响this的行为,在前一个例子中,我们在定义的object中为成员f添加了一个匿名函数,然而,我们能
更简便的先定义这些函数然后再将其附属到o.f上。这样做this的行为也是一致。

这个例子只有o对象中的f才会令这个函数被调用。

同样的,this绑定只会被最当前的引用所决定。在接下来的例子中,当我们调用这个function,把它当作o.b对象的g方法调用。在执行中,this会附属到o.b上。这个对象本身作为o的成员没有结果,其返回结果就是当前引用。
如下例:

o.b = {g: independent, prop:37}
console.log(o.b.g());    //返回37


只要方法是定义在对象的原型链中上面的调用同样的仍然正确,如果方法在一个对象的原型链中,this对象指向调用这个方法的对象,就像这个方法存在于这个对象中一样。…在原型链中


var o = {
    f:function(){return this.a + this.b;}
}
var p = Object.create(o);
p.a = 1;
p.b = 5;
console.log(p.f());   //6

…或者作为一个getter或者setter在此例中,p对象并没有它自己的实例f属性,它继承于原型链。但是没有关系f能在o对象中找到;查找以一个p.f的引用开始,因此这个function中的this取对象p的引用值。也就是说,当f函数作为p的对象被调用,它的this指向p。这是Javascript原型继承中非常有趣的特征。

Again, the same notion holds true when a function is invoked from a getter or a setter. A function used as getter or setter has its this bound to the object from which the property is being set or gotten.
当方法被getter或者setter调用同样的概念仍然成立,当对象的属性被set或者是gotten时,它的getter或者setter函数中的this对象会被绑定到当前对象。


function modulus(){
    return Math.sqrt(this.re*this.re + this.im*this.im);
}

var o = {
    re : 1,
    im : -1,
    get phase(){
        return Math.atan2(this.im,this.re);
    }
};

Object.defineProperty(o,'modulus',{get: modulus,enumerable: true,configurable:true});

console.log(o.phase,o.modulus); //返回-7.86  1.414

When a function is used as a constructor (with the new keyword), its this is bound to new object being constructed.As a Constructor作为构造器

Note: while the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value isn’t an object, then the this object is returned).
当函数作为构造器(使用new关键词),它的this绑定为新构造的对象。
注意:当然默认的构造器返回的this对象为当前调用对象,它能被当前对象中return的新对象所取代(如果对象的返回值不是对象,那么this仍指向当前对象)。

/*注意中示例*/
var o = {
	a : 12,
	f : function(){
		return this.a;
	}
	};
var p = {
	a : 21,
	f : function(){
	return o.f();
	}
	};

console.log(p.f()); //返回12

/*
 * Constructors work like this:
 *
 * function MyConstructor(){
 *   // Actual function body code goes here.  Create properties on |this| as
 *   // desired by assigning to them.  E.g.,
 *   this.fum = "nom";
 *   // et cetera...
 *
 *   // If the function has a return statement that returns an object, that
 *   // object will be the result of the |new| expression.  Otherwise, the
 *   // result of the expression is the object currently bound to |this|
 *   // (i.e., the common case most usually seen).
 * }
 */
 
 function C(){
    this.a = 37;
 }
 var  o = new C();
 console.log(o.a);   //返回37
 
 function C2(){
    this.a = 38;
    return {a:38};
}
o = new C2();
console.log(o.a);    //返回38


构造器示例

在上一个例子中(c2),因为有一个对象在构建中返回,所以this对象绑定到了返回的对象上。

call和apply

在function内部使用this关键词时,它的值可以在使用call或apply(所有的function对象都继承自Function.prototype)调用时绑定为该函数中传入的对象。

function add(c,d) {
    return this.a + this.b + c + d;
}
var o = {
    a : 2,
    b : 2
}
console.log(add.call(o,2,2)); //返回8

console.log(add.apply(o,[2,4])); //返回10

ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.Bound functions 绑定函数

ECMAScript 5介绍 Function.prototype.bind.调用f.bind(someObject).创建一个新的function拥有同样的内容和作用域比如f,但是this对象仍然出现在原来的function中,在新的function中他仍然永久的绑定第一个参数上比如下面的g绑定的参数,不管这个function被调用了多少次。

function f(){
    return this.a;
}

var g = f.bind({a : "penouc"});
console.log(g());

var  o = {a : 37,f : f, g : g};
console.log(o.f(),o.g());

当一个function被用作为一个事件处理程序,它的this被设置为当前的元素(一些浏览器并不遵循这个规则而是动态的添加方法比如使用addEventListener)。As a DOM event handler 作为一个DOM事件处理程序

//当元素被调用,其被激活为蓝色
function bluify(e) {
    console.log(this === e.target);
    console.log(this === e.currentTarget);
    this.style.backgroundColor = "#A5D9F3";
}

//获得整个document的元素
var elements = document.getElementsByTagsName("*");

//当元素被点击时元素被调用
for(var i = 0; i < elements.length; i++) {
    elements[i].addEventListener('click',bluify,false);
}


当代码被行内事件处理程序调用,它的this就是当前元素:In an in-line event handler 在行内的事件处理程序

<button οnclick="alert(this.tagName.toLowerCase());">Show this</button>
Show this
以上警告为button。注意无论如何只有在有外层代码才设置为这样:

<button οnclick="alert((function(){return this}()));">Show inner this</button>





在这个例子中,内部的function的this并未设置因此返回为window/global对象。

javascript this 基础 call apply