在javascript中的构造函数创建对象时,常常使用this,但是this到底是什么,其实有一遍英文的文章 介绍的很详细:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
这里我把它翻译出来,自己也深刻的理解和体会一下。原文翻译如下:
Javascript中this关键字的行为与其他的语言表现的非常不一样 (比如说C++的this指针一般都是指向当前对象的),而且在严格模式和非严格模式上也还不一样。
在大多数的情况下,this的值是由函数如何调用来决定的,其不能再执行的过程中赋值,而且可能在同一个函数执行的过程中也不一样。ES5中介绍了bind的方法来设置this的值。
了解具体的this指针,分为下面两种情况
Global context (全局环境)
在全局的执行环境中(函数外),不论是严格模式还是非严格模式,this 表示的全局对象, 实例代码如下:
console.log(this.document === document); // true
// 在浏览器中,window object就是一个全局的对象
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37
Function context (函数环境)
在函数环境中,this代表的值取决于函数是如何被调用的。
- 简单函数调用
function f1(){
return this;
}
f1() === window; // 全局对象
在严格模式下,this的值默认为undefined,this是在进入执行环境中被设置的,其可以被设置成任何值,如null,或者42,等。
function f2(){
"use strict"; // see strict mode
return this;
}
f2() === undefined;
- 作为对象方法
当函数作为对象方法被调用时,this就被设置成调用方法的对象。在下面的例子中,当o.f()调用时,this是绑定到o对象上的。
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
值得注意的是,this的值不会受函数在哪里定义影响,在上面的例子中,函数f是在定义o的时候内联进去的,我们还可以在稍后给制定,如下的代码,执行也是一样的。
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
这也验证了this仅仅取决于f函数是作为对象o的成员函数调用的。
还有,this仅仅取决于最后离调用函数最近的类,在下面的例子中,函数中的this是o.b对象
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42
1) this在对象原型链
如果方法是在对象的原型链上,this依然指向的当前的对象。
var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
在上面的例子中,p对象没有f属性,其是从原型中继承过来的,但是这不妨碍this被赋值成p对象,并且在f函数中用this对象查看a与b。
2) this 在get和set属性方法中
在get和set方法中依然用相同的表现。
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); // logs -0.78 1.4142
- 构造函数
当函数作为构造函数(用this关键字),this就是新创建的对象。
注意:虽然this默认是构造函数的返回的对象,但是,其可以被修改成其他的对象(当返回值不是object)具体的例子代码如下:
/*
* 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上增加属性,方法等。
* 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).
// 如何函数有return语句返回一个对象,这个对象就是new 表达式
// 的值,否则,其返回的就是绑定了this指针的object
* }
*/
function C(){
this.a = 37;
}
var o = new C();
console.log(o.a); // logs 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
在C2的例子中,因为有一个新对象返回,这个this绑定的新的object其实是被丢球了没有用。其实导致this.a = 37是一段code执行了,但是没有任何效果。
在执行了
- call and apply (call函数和apply函数)
当使用call和apply执行的时候,this就是调用call,apply的第一个参数。
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
// The first parameter is the object to use as
// 'this', subsequent parameters are passed as
// arguments in the function call
// this代表的这个对象就是o.
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// The first parameter is the object to use as
// 'this', the second is an array whose
// members are used as the arguments in the function call
// this代表的这个对象就是o.
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
注意的是,如果call和apply的第一个参数不是一个对象,其也会调用toObject方法来调用这个对象。如下面的例子,会将7先转成Number对象。
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
- bind方法
ECMAScript 5 引入了新方法 Function.prototype.bind(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind),调用f.bind(someObject)会创建一个与f一样的新函数,不同的是,新函数的this将是bind函数的第一个参数。参考下面的例子:
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var o = {a:37, f:f, g:g};
console.log(o.f(), o.g()); // 37, azerty
- DOM 事件回调函数
当函数被用作时间回调是,其this就是发送时间的对象。例如下面的代码:
// When called as a listener, turns the related element blue
function bluify(e){
// Always true
console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
// Get a list of every element in the document
var elements = document.getElementsByTagName('*');
// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for(var i=0 ; i<elements.length ; i++){
elements[i].addEventListener('click', bluify, false);
}