在绝大多数情况下,函数的调用方式决定了this的值
全局环境
无论是否在严格模式下,在全局执行环境中,this都指向全局对象·
在全局作用域中调用一个函数时,this总是指向Global对象(在浏览器中指向window)
函数(运行内)环境
在函数内部,this的值取决于函数被调用的方式
1.简单调用
非严格模式
function f1() { console.log(this); } // 在浏览器环境 f1();//window // 在Node环境 f1();//global
严格模式
在严格模式下,如果this没有被执行环境(execution context)或者称为上下文,this会保持它进入执行环境时的值,所以下面this会被默认为undefined
function f2() { 'use strict'; console.log(this); } f2(); //undefined
使用call()或者apply()方法,改变this的指向
// 如果想把this的值从一个环境传到另一个,就可以调用call()或者apply()方法 var o = { a: 'Customs' }; var o1 = { a: 'Customs1' }; var o2 = { a: 'Customs2' }; var a = 'Global'; function whatThis(arg) { console.log(this.a); } whatThis(); //Global whatThis.call(o); //Customs whatThis.apply(o); //Customs whatThis.call(o1); //Customs1 whatThis.apply(o1); //Customs1 whatThis.call(o2); //Customs2 whatThis.apply(o2); //Customs2
强制指向,即改变函数的调用对象
两者有何异同?
apply(thisObj,[argsArray])
call(thisObj,arg1,arg2,arg3)
call()与apply()方法类似,区别就是接受的参数形式不一样
apply()接受的是数组;call()接受的是以逗号分隔的参数
使用
call
和 apply
函数的时候要注意,如果传递给 this
的值不是一个对象,JavaScript 会尝试使用内部 ToObject
操作将其转换为对象。因此,如果传递的值是一个原始值比如
7
或 'foo'
,那么就会使用相关构造函数将它转换为对象,所以原始值 7
会被转换为对象,像 new Number(7)
这样,而字符串 'foo'
转化成 new String('foo')
这样,function bar() { console.log(Object.prototype.toString.call(this)); } //原始值 7 被隐式转换为对象 bar.call(7); // [object Number]
2.作为对象的方法调用
当函数作为对象的方法调用,他们的this是调用该函数的对象
var x4 = 44; function f4() { console.log(this.x4); //{x:55,say:f4} this指向o4 } var o4 = {}; o4.x4 = 55; o4.say = f4; o4.say(); // 55
var x5 = 56; var o5 = { x5: 66, f5: function() {
console.log(this) // {x5:66,f5:f} this指向o5
// console.log(this.x5);//66
return this.x5; } }; console.log(o5.f5()); //66
原型链中的this
对于原型链上某处定义的方法,同样也适用, 如果该方法存在于对象的原型链上,那么this的指向的是调用该方法的对象
var oo = { f: function() { return this.a + this.b; } }; var p = Object.create(oo); p.a = 1; p.b = 2; console.log(p.f()); // 3 // 解析:对象p没有自己的f属性,该属性继承自原型, // 对于f的查找过程中,最终在对象oo中找到f属性,查找的过程是p.f的引用开始的,所以this指向p // 也就是说,因为f是作为p的方法调用的,所以this指向p
getter和setter中的this
当一个函数在一个setter或者getter中被调用
用作getter或者setter的函数都会把this绑定到设置或者获取属性的对象
function sum() { console.log(this); //{a: 1,average: 2,b: 2, c: 3,sum: 6} return this.a + this.b + this.c; } var oo1 = { a: 1, b: 2, c: 3, get average() { console.log(this);//{a: 1,average: 2,b: 2, c: 3,sum: 6} return (this.a + this.b + this.c) / 3; } }; Object.defineProperty(oo1, 'sum', { get: sum, enumerable: true, configurable: true }); console.log(oo1.average, oo1.sum); // 2,6
3.作为构造函数
当一个函数作为构造函数时(使用new关键字),他的this指向用构造函数创建的对象
function Test() { this.x = 3; } var obj1 = new Test(); console.log(obj1.x); // 3 // 解析:this指向Test的实例,即obj1 obj1.x = 5; console.log(obj1.x); // 5
4.bind()方法
ES5引入Function.prototype.bind()
调用 f.bind()方法会创建一个与 f具有相同的函数体和作用域的函数
但是在这个函数中,this将永久性的被绑定到了bind的第一个参数,无论函数是怎么样调用的
var a3 = 'Global'; function f3() { console.log(this.a3); //zhangsan return this.a3; } var g = f3.bind({ a3: 'zhangsan' }); console.log(g()); // zhangsan var h = g.bind({ a3: 'haha' }); // bind只生效一次,再次修改也不会生效 console.log(h()); // zhangsan var o3 = { a3: 37, f3: f3, g: g, h: h }; console.log(o3.f3(), o3.g(), o3.h()); // 37,"zhangsan","zhangsan"
5.作为一个DOM时间处理函数
当函数被用作事件处理函数时,它的this
指向触发事件的元素
6.作为一个内联事件处理函数
当代码被内联on-event 处理函数调用时,它的this
指向监听器所在的DOM元素
参考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this
http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html