一、了解this
在面向对象的语言中 this 就是当前对象的一个引用,即当前环境的上下文对象,面向对象语言中 this 表示当前对象的一个引用。在JS中this会随着环境的改变而改变,此所谓世界上唯一不变的就是改变。
二、this指向总结
1、单独使用 this
这种情况应该是最好理解的,this既不在方法中也不再对象中,而是出现在文档的第一层,默认情况下this当然指向当前文档这一对象。(严格模式下依然是指向全局对象)
2、this 在定义的函数中
严格模式下("use strict"),函数是没有绑定到 this 上的,所以此时使用是 undefined。非严格模式下,函数的所属者默认绑定到 this 上,此时 this 就指向函数的所有者,如果你在全局定义的函数那么 this 就指向全局对象。
// 非严格模式
<script>
var name = "xxx";
function test() {
let name = "yyy";
console.log(this.name); // xxx
console.log(name); // yyy //注意:如果函数内部未定义name则会向外寻找, 一直到最上一层,找到则打印,未找到打印 undefined
}
test1();
</script>
// 严格模式
<script>
// 开始严格模式
"use strict";
var name = "xxx";
function test() {
var name = "yyy";
console.log(this.name); // 报错不打印,提示name未定义
}
test1();
</script>
3、this 在定义的对象方法中
如果 this 出现在对象的方法中, 那么当前函数归属于当前的对象,所以函数内的 this 的指向就是当前对象。
<script>
// 开启严格模式
"use strict";
var name = "ypf";
var person = {
name: "John",
log: function() {
console.log(this.name); // John
console.log(name); // ypf // 区别于在函数中的打印
}
};
this.person.log(); // person.log(); 此时两种写法等效
</script>
这个东西要灵活理解,就比如下面这个例子,对象中的属性的返回值是一个匿名函数,而匿名函数的归属于Windows对象,所以这个例子的匿名函数中的 this 就不指向 person 对象。
<script>
// 开启严格模式
// "use strict";
var name = "ypf";
var person = {
name: "John",
name2: this.name,
log: function () {
console.log(this.name); // John
return function () {
console.log(this.name); // ypf // 函数返回的是一个匿名函数,而匿名函数归属于Windows对象
console.log(name); // ypf
}
}
};
this.person.log()();
console.log(person.name2); // ypf // 此时 this 就和person的归属对象保持一致
</script>
下面是构造函数的例子,所谓构造函数,就是通过这个函数生成一个新对象,这时,this就指向这个对象,区别于对象中的函数。
<script>
var testStr = "ypf";
function Demo() {
this.testStr = 'gj';
this.fun = function() {
console.log(this.testStr);
}
}
let a = new Demo();
console.log(a.testStr); // gj
a.fun() // gj
</script>
4、显式函数绑定 (apply、call、bind )
显示绑定就不用过多解释了就是指那打那,apply、call、bind 都可以改变 this 的指向,区别在于返回值和第二个参数,大家可以自行百度。
<script>
// 开启严格模式
// "use strict";
var person1 = {
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName: "李",
lastName: "婉莹",
}
console.log(person1.fullName.call(person2)); // 李婉莹
</script>
三、牛刀小试
实例1 :腾讯面试题
<script>
var x = 20;
var a = {
x: 15,
fn: function () {
var x = 30;
return function () {
return this.x
}
}
}
console.log(a.fn());
console.log((a.fn())());
console.log(a.fn()());
console.log(a.fn()() == (a.fn())());
console.log(a.fn().call(this));
console.log(a.fn().call(a));
// 答案
// 1.console.log(a.fn());
// 对象调用方法,返回了一个方法。
// # function() {return this.x}
// 2.console.log((a.fn())());
// a.fn()返回的是一个函数,()()这是自执行表达式。this -> window
// # 20
// 3.console.log(a.fn()());
// a.fn()相当于在全局定义了一个函数,然后再自己调用执行。this -> window
// # 20
// 4.console.log(a.fn()() == (a.fn())());
// # true
// 5.console.log(a.fn().call(this));
// 这段代码在全局环境中执行,this -> window
// # 20
// 6.console.log(a.fn().call(a));
// this -> a
// # 15
</script>
实例2:this指向Foo
<script>
function Foo() {
getName = function() {
alert(1);
}
return this;
}
Foo.getName = function() {
alert(2);
}
Foo.prototype.getName = function() {
alert(3);
}
var getName = function() {
alert(4);
}
function getName() {
alert(5);
}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo().getName(); // 3
</script>
实例3:this指向window
</script>
function Foo() {
var getName = function() {
alert(1);
}
return this;
}
Foo.getName = function() {
alert(2);
}
Foo.prototype.getName = function() {
alert(3);
}
var getName = function() {
alert(4);
}
function getName() {
alert(5);
}
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 4
getName(); // 4
new Foo().getName(); // 3
</script>