在JavaScript中this
关键字非常灵活, 在不同的情况下有不同的含义. 对于初学者来说 比较难以掌握, 即使是有经验的开发人员, 亦容易犯错. Google 一下 understanding this keyword in javascript
有一大把相关的网页, 足以证明this
给开发者带来的困 扰.
this
含义总则万剑归宗, 万宗归一. 总得来说,
this
指定义处(非运行处)上下文对象.下面根据不同的情景阐述一下.
在浏览器中运行以下示例, 会发现, this
都是指向window
对象.
var test = function (value) { this.hello = value; console.log(‘this in test() ‘) console.log(this); console.log(window.hello); }; var obj = {}; var wrapper = function (value) { console.log(‘this in wrapper() ‘); console.log(this); test(value || ‘value from wrapper‘); }; //在全局下运行, 故`this`指向全局对象, 浏览器中即windows. //若运行在node.js环境中, 指向global test(‘value from window‘); //同test() wrapper(); //此时, 使用call改变了wrapper函数中`this`的指向. //在wrapper函数中, `this`指向 obj 对象. // //虽然在wrapper函数中运行test函数, 但在test函数中`this`依然指向全局对象. //这种情况很好的说明`this`的含义总则: 指定义处(非运行处)上下文对象. // wrapper.call(obj, ‘value from wrapper apply‘);
在对象方法中, this
总是指向对象本身.
var uncleWang = { _name: ‘WangXiaobo‘, getName: function () { //`this` 指向uncleWang 对象 return this._name; }, displayName: function () { //`this` 指向uncleWang 对象 var name = this.getName(); //显示 The name is WangXiaobo console.log(‘The name is ‘ + name); } };
若一个纯函数变成了一个对象的方法, 函数作为对象方法时, this
指向对象. 但作为纯函 数调用时, this
依然指向定义处的上下文对象.
window._name = ‘window‘; var sayName = function () { console.log(‘My name is ‘ + this._name); } uncleWang.sayName = sayName; //作为对象方法调用, `this`指向对象 //显示 My name is WangXiaobo uncleWang.sayName(); //纯函数调用, `this`指向定义处的上下文对象 //显示 My name is window sayName();
this
都指向类实例.this
指向构造函数本身, 因为构造函数本身也是对象.
/** * @param {String} name */ function Person (name) { this._name = name; } //类方法添加至构造函数的prototype对象上 Person.prototype.getName = function () { return this._name; }; Person.prototype.displayName = function () { var name = this.getName(); console.log(‘name: ‘ + name); }; Person._className = ‘Person‘; //类方法中, `this`指向构造函数本身, 因为构造函数本身也是对象. Person.getNameOfClass = function () { return this._className; }; console.log(‘name of class: ‘ + Person.getNameOfClass()); //使用new创建类实例 var uncleWang = new Person(‘WangXiaobo‘); uncleWang.displayName();
在JavaScript中, 函数有call, apply和bind方法, 都可以用于改变函数的执行上下文. 有 关这些方法详细说明可参考:
在函数中, this
指向这些方法绑定的对象, 如果绑定的对象是undefined
或者null
, this
指向全局上下文.
window.hello = ‘hello of window‘; var obj = { hello: ‘hello of obj‘ }; var sayHello = function () { console.log(this.hello); }; //纯函数执行, `this`指向定义处上下文 //显示 hello of window sayHello(); //call, apply 方法运行函数并使得运行时函数中`this`指向obj对象 sayHello.call(obj); sayHello.apply(obj); //bind返回一个包装过的函数 var bindedSayHello = sayHello.bind(obj); //执行包装函数时, 会调用sayHello函数, 且sayHello函数中`this`指向obj对象 bindedSayHello(); // var obj2 = { hello: ‘hello of obj2‘ }; //即使使用call或apply改变包装函数中`this`的上下文, 但执行sayHello函数时, sayHello函 //数中`this`依然指向obj对象 //有一点点难于理解, 是吧? bindedSayHello.call(obj2);
bind有时难于理解, 可以参考以下bind的简单实现以理解其原理.
/** * @param {Function} fn * @param {Object} context * @return {Function} */ var bind = function (fn, context) { return function () { fn.apply(context, arguments); }; } var bindedSayHello2 = bind(sayHello, obj); bindedSayHello2();
由于各个浏览器实现的不一致, DOM事件监听器中的this
会给开发者带来一点困扰.
Html元素绑定事件监听器的方式一般有以下几种:
<a ... onclick="alert(‘link‘)" ...
link.onclick = function () {...};
addEventListener
方法绑定事件attachEvent
方法绑定事件可以用以下html代码测试在不同浏览器下, 使用不同方式绑定的监听器中this
的指向.
<!DOCTYPE html> <html> <head> <title>test this</title> <meta charset="utf-8" /> </head> <body> <h1> test this </h1> <div> <p id="inline" onclick="console.log(this)" > <input type="button" value="test inline" /> </p> <p id="dom0" > <input type="button" value="test dom level 0" /> </p> <p id="dom2-w3c" > <input type="button" value="test dom level 2 for w3c" /> (only available in browser that supports DOM2) </p> <p id="dom-ie" > <input type="button" value="test dom level 2 for ie" /> (only available in IE) </p> </div> <script> var dom0= document.getElementById(‘dom0‘), dom2W3c = document.getElementById(‘dom2-w3c‘), domIe = document.getElementById(‘dom-ie‘); dom0.onclick = function () { console.log(this); }; if (domIe.attachEvent) { domIe.attachEvent(‘onclick‘, function () { console.log(this); }, false); } if (dom2W3c.addEventListener != null) { dom2W3c.addEventListener(‘click‘, function () { console.log(this); }, false); } </script> </body> </html>
如果在不同的浏览器测试以上代码, 可以总结做成以下图表.
浏览器 | 行内绑定 | DOM Level 0 | addEventListener | attachEvent |
---|---|---|---|---|
w3c 系列 | Element | Element | Element | X |
ie 系列 | Element | Element | Element (ie9+) | Window |
Element
: this
指向被绑定的元素Window
: this
指向window
对象X
: 浏览器不支持某些特性, 无法测试根据以上图表, 我们很容易得出结论:
attachEvent
方式绑定的监听器中, this
指向window
对象.this
指向被绑定的元素.
event.target
, 虽然在某些情况下二者可能是同一对象.@end
原文:http://blog.csdn.net/fudesign2008/article/details/18460387