this
在全局执行上下文(函数之外),this引用的是全局对象.
console.log(this.document === 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 f1(){ return this; } f1() === window; // global object
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
假如 o 对象只申明了一个属性,其f方法在开始声明时还没有被定义,然后通过o.f直接被赋值为其他方法,其最后的效果也是一样的,只是定义的前后问题,this依然指向的是o这个对象:
var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // logs 37
这个例子说明的是f函数的调用,是作为o的成员方法来执行.
我们继续来看,如果我们给o设定另外一个成员属性b赋予为一个对象,看下面这个例子,这时候,this该指向的是谁呢? 前面已经说过,this指向的是对象本身,所以o.b作为一个对象,同样这个对象的this指向的是他自己o.b.
o.b = {g: independent, prop: 42}; console.log(o.b.g()); // logs 42
同样的概念也使用对象原型链中
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没有自己的属性.它继承了o的属性.所以这时候通过p来调用f方法,this指向的是p,这是对象原型模式.这里就是javascript中的原型继承模式.
再次,用相同的概念也适用于getter和setter.函数使用getter或者setter来绑定到对象的属性.
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
.当一个函数作为一个构造函数使用(同构new来构造).this这时候指向的是函数构造出来的对象.
提示: 虽然默认构造函数返回对象引用,它也可以返回其他对象 .
/* * 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); // logs 37 function C2(){ this.a = 37; return {a:38}; } o = new C2(); console.log(o.a); // logs 38
在最后的例子中(C2),因为一个对象在构造函数期间返回,这个新对象就会被丢弃.("this.a=37"; 其实没什么作用的代码.但是他也不是完全是死码,因为他被执行了.但是没有影响到外面的代码执行.)
call
和 apply
一个函数在内部使用this,通过使用call或者apply方法将它的值绑定到一个特殊的对象.所有方法继承Function.prototype.
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 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 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
我们来看下下面的这个列子.bar.call(7)这一行代码,将第一个参数为一个数值,则这时候的bar方法里面的this是指向Number.到这里,你可以试试执行另外的一行代码 new Number(10).toString(),看看效果.
function bar() { console.log(Object.prototype.toString.call(this)); } bar.call(7); // [object Number]
bind方法
ECMAScript 5 介绍了 Function.prototype.bind
. 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将是指向这个元素的本身事件(使用addEventListener添加监听器事件中,有些浏览器不遵守公约,有自己的一套做法.)
// 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); }
内联事件处理
当代码在元素上进行调用处理,this指向的是这个DOM元素.
<button onclick="alert(this.tagName.toLowerCase());"> Show this </button>
上面显示的是这个按钮. 记住只有这种方式,返回的是这个元素.
<button onclick="alert((function(){return this}()));"> Show inner this </button>
在这个例子中,内部函数this没有被设置,因此它返回的全局对象window.