一、this指向构造函数实例化对象
在上篇文章中,我们提到了使用new和不使用new调用构造函数的区别,如下例:
function Benjamin(username, sex) { this.username = username; this.sex = sex; } var benjamin = new Benjamin("zuojj", "male"); //Outputs: Benjamin{sex: "male",username: "zuojj"} console.log(benjamin); var ben = Benjamin("zhangsan", "female"); //Outputs: undefined console.log(ben);
当构造函数当做普通函数被调用时,并没有返回值,同时this指向全局对象。那么我们如何来避免因为缺少new关键字,而产生的问题呢?
function Benjamin(username, sex) { //Check whether "this" is a "Benjamin" object if(this instanceof Benjamin) { this.username = username; this.sex = sex; }else { return new Benjamin(username, sex); } } var benjamin = new Benjamin("zuojj", "male"); //Outputs: Benjamin{sex: "male",username: "zuojj"} console.log(benjamin); var ben = Benjamin("zhangsan", "female"); //Outputs: Benjamin {username: "zhangsan", sex: "female"} console.log(ben);
在上例中,我们首先检查this是否是Benjammin的实例,如果不是,使用new自动调用构造函数,并实例化,这意味着,我们不再需要担心,遗漏new关键字实例化构造函数。当然这样我们可能会养成一个坏的习惯,如果避免这种现象呢?我们可以抛出一个错误,像下面这样:
function Benjamin(username, sex) { //Check whether "this" is a "Benjamin" object if(this instanceof Benjamin) { this.username = username; this.sex = sex; }else { // If not, throw error. throw new Error("`Benjamin` invoked without `new`"); } }
二、this指向调用该函数的对象
看下面的例子:
var x = 10; var obj = { x: 10, output: function() { //Outputs: true console.log(this === obj); return this.x; }, innerobj: { x: 30, output: function() { //Outputs: true console.log(this === obj.innerobj); return this.x; } } }; //Outputs: 10 console.log(obj.output()); //Outputs: 30 console.log(obj.innerobj.output());
三、this指向全局对象
在上面讨论构造函数的时候我们也讨论到不适用new的时候,this会指向全局对象,下面我们来看看两种常见的容易犯错的实例:
var x = 100; var obj = { x: 10, output: function() { (function() { //Outputs: true console.log(this === window); //Outputs: Inner: 100 console.log("Inner:" + this.x); })(); return this.x; } }; //Outputs: 10 console.log(obj.output());
在使用闭包的时候,作用域发生变化,this指向window(浏览器中)。
var x = 100; var obj = { x: 10, output: function() { return this.x; } }; var output = obj.output; //Outputs: 10 console.log(obj.output()); //Outputs: 100 console.log(output()); var obj2 = { x: 30, output: obj.output } //Outputs: 30 console.log(obj2.output());
此时this始终指向函数调用时的对象。
四、this指向apply/call()方法指派的对象
var x = 100; var obj = { x: 10, output: function() { return this.x; } }; //Outputs: 10 console.log(obj.output()); var obj2 = { x: 40, output: obj.output } //Outputs: 40 console.log(obj.output.call(obj2)); //Outputs: 10 console.log(obj2.output.apply(obj));
五、callback函数內的this指向调用该callback的函数的this所指向的对象
//<input type="text" value="3" id="txt_username"> $("#username").on("click", function() { console.log(this.value); });
六、Function.prototype.bind中的this
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
实例一:
function person() { return this.name; } //Function.prototype.bind var per = person.bind({ name: "zuojj" }); console.log(per); var obj = { name: "Ben", person: person, per: per }; //Outputs: Ben, zuojj console.log(obj.person(), obj.per());
实例二:
this.x = 9; var module = { x: 81, getX: function() { return this.x; } }; //Outputs: 81 console.log(module.getX()); var getX = module.getX; //Outputs: 9, because in this case, "this" refers to the global object console.log(getX); // create a new function with 'this' bound to module var boundGetX = getX.bind(module); //Outputs: 81 console.log(boundGetX());