JavaScript的this迷之指向是不是弄晕了你,我是被转的晕头转向,所以来总结一下this的指向问题。
this的指向总体可以分为四种情况:
- 直接调用
- 作为对象方法调用
- 构造函数调用
- call()跟apply()方法调用
在说this的指向之前,我们先要知道this是在函数调用的时候确定的,这使得我们可以非常灵活的使用this,所以这才叫迷之this。
- 直接调用
废话不多说,直接上码
var name = "xiaoming";
function getName() {
var name = "xioahong";
console.log(this.name); // xiaoming
console.log(this === window); // true
}
getName();
上面的例子可以说明函数独立调用的使用this指向全局window,但是如果在严格模式会报错。
顺便一提,ES6已经默认使用严格模式。
看了上面的例子,不要以为只有全局作用域独立调用函数,this才指向全局window,其实在任何作用域像 函数名() 这样的独立调用函数的this都指向全局window。
function getName() {
function personName() {
console.log(this === window); // true
}
return personName;
}
getName()();
或许有人看不懂getName()();这个的意思,其实就是在调用getName函数再处理它的返回值,就相当于下面的例子。
function getName() {
function personName() {
console.log(this === window); // true
}
personName();
}
getName();
而在接触this后,你是否想改变this的指向,可是this的指向是不可以改变的,我们先来看下this指向不可改变。
var obj = {
name: "xiaoming"
}
function getName() {
this = obj;
console.log(this.name);
}
getName(); // 运行报错
2.作为对象的方法的调用
先上两个例子
var name = "xiaohong";
var obj = {
name: "xiaoming",
getName: function() {
console.log(this.name); // xiaoming
console.log(this === obj); // true
}
}
obj.getName();
(obj.getName)(); // 结果与上面调用方式相同
// 这只是在引用一个函数,所以this指向保持不变
var name = "xiaohong";
var obj = {
name: "xiaoming",
getName: function() {
console.log(this.name); // xiaohong
console.log(this === obj); // false
}
}
var fn = obj.getName;
fn();
乍一看上面两个例子没有什么区别,但是区别很大:
例1调用obj对象里面的getName()方法,所以this指向obj;
例2将obj.getName的引用赋值给变量fn,之后又独立调用,说以this指向了全局Window
在此总结:
如果调用函数被一个对象所拥有,则该函数内部的this指向该对象。
如果函数单独调用,则this指向全局window,在严格模式下报错。
(调用匿名函数在我的理解中也相当于函数独立调用)
来个简单的自执行函数来证明一下
(function() {
console.log(this === window); // true
})();
我们来看下下面这个例子
var name = "global";
var obj = {
name: "local",
getName: function() {
return function() {
// 该匿名函数为闭包
return this.name; // 返回的是?
};
}
};
console.log(obj.getName()());
这个答案当然是 "global" 。因为我们知道每个函数在调用的时候会获取两个对象:this和arguments。而内部函数在搜索这个两个对象时只会搜索到其活动对象为止。而匿名函数的执行环境具有全局性,所以这个this就指向了全局window。
但我们要访问匿名函数的外部函数变量的话要怎么做?看这里。
var name = "global";
var obj = {
name: "local",
getName: function() {
var that = this;
return function() {
return that.name; // local
};
}
};
console.log(obj.getName());
我们不可以改变this的值,但我们可以把this用变量存储起来,这样this的指向就不会变了。
3.构造函数调用 function Person(name, age) {
this.name = name; // 此处this的指向是?
this.age = age;
}
var person = new Person("xiaoming", 22);
console.log("name:" + person.name + ",age:" + person.age);
参考JavaScript高级程序设计,我们可以知道new操作符做了四件事:
- 创建一个新对象
- 将构造函数的作用域赋给了新对象(因此this指向了该对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
所以上面的打印结果是: name:xiaoming,age:22
4.使用call()跟apply()方法绑定this先来看下定义
call方法:
语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定义:调用一个对象的一个方法,以另一个对象替换当前对象。
说明:
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj
指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。apply方法:
语法:apply([thisObj[,argArray]])
定义:应用某一对象的一个方法,用另一个对象替换当前对象。
说明:
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数
我们来看下怎么绑定this
var obj = {
name: "xiaoming"
}
function getName() {
console.log(this.name); // xiaoming
}
getName.call(obj);
其实在我的理解中call跟apply是没有什么区别,只是传递参数的形式不一样。
call():一个一个的传递参数;
apply():以数组的形式传递。
var obj = {
num1: 1
}
function count(num2, num3) {
console.log(this.num1 + num2 + num3);
}
count.call(obj, 1, 1); // 3
count.apply(obj, [1, 1]); // 3
使用call()跟apply()可以借用其他对象的方法。
例如:借用Math()对象的最大值方法找出数组中的最大值
var
arr = [2,34,54,23,233,44],
maxNum = Math.max.apply(Math, arr);
console.log(maxNum); // 233
作者: 关于郑州想的都是你
链接:http://www.imooc.com/article/17159
来源:慕课网