在这篇文章中,你将会弄清this关键字指的是什么,在为你讲解this
同时,你还将学习到.call
,.apply
,.bind
和new
以及箭头函数等知识。数组
this
是JavaScript中很特别的一个关键字,被自动定义在全部函数做用域中,可是它即不指向函数自身也不指向函数的词法做用域,它指向的是调用函数的对象。bash
要判断this
指向哪里,咱们必须理解每一个函数的this
并非在声明时就被绑定的,而是在调用时被绑定。
正如上文所说this
指向的是调用函数的对象,因此要判断this
到底指向哪里,首先咱们要知道 “是哪一个对象调用了函数?”app
举个例子来帮助同窗们理解这一点:函数
例子1:学习
123function person(name) {
console.log(name);
}
复制代码
能够看到例子里声明了一个person
函数,接收一个name
参数,想知道name
会打印出什么,必须得看person
函数调用过程当中传入参数是什么。一样的道理想判断this
指向哪里,就得看函数调用方式是什么。ui
例2:this
123456789101112function person() {
console.log(this);
}
function personStrict() {
'use strict'
console.log(this);
}
person(); // window
personStrict(); // undefined
复制代码
能够看到,函数被直接调用时,就至关于全局对象调用的;这样它的 this
就指向全局对象:window
;spa
例3:code
1234567(function(){
//'use strict'
function getDoc() {
console.log(this.document);
}
getDoc();
})();
复制代码
能够看到,若是程序在非严格模式下运行,不会有错误抛出,那是由于在全局对象window
中存在一个名为document
的属性,而在严格模式下,因为此时this
指向undefined
,因而抛出一个错误。cdn
例4:
12345678let name = 'window';
let person = {
name : 'Heternally',
getName : function(){
console.log(this.name);
}
}
person.getName(); // 'Heternally'
复制代码
123456789let name = 'window';
let person = {
name : 'Heternally',
getName
}
function getName(){
console.log(this.name)
}
person.getName(); // 'Heternally'
复制代码
能够看到在上面👆例子中,getName函数是对象person调用的,因此打印出来的值是person中name的值
例5:
12345678910let name = 'window';
let person = {
name : 'Heternally',
getName : function () {
console.log(this.name);
}
}
let getName = person.getName;
getName(); // 'window'
复制代码
例5对例4作了一点点小改动,能够看到打印出的结果就是window
了,这是由于getName
函数最终仍是被window
调用,因此这个this
指向的是window
这又应了上文的话,this
的指向不能在声明的时候肯定,而是取决于谁调用了它
例6:
12345678910111213141516171819202122232425let person1 = {
name : 'person1',
getThis: function () {
console.log(this);
}
}
let person2 = {
name : 'person2',
getThis: function () {
return person1.getThis();
}
}
let person3 = {
name : 'person3',
getThis: function () {
var getThis3 = person1.getThis;
return getThis3();
}
}
person1.getThis(); // person1
person2.getThis(); // person1
person3.getThis(); // window
复制代码
看到这可能有同窗会问,不是说this
的指向取决于谁调用了它吗,那为何person3.getThis()
打印出来的是window
呢,由于在person3.getThis
里,调用this
的函数是getThis3
,因此此时this
指向了window
由上面👆几个例子能够得出,this
指向最后调用它的那个对象。
这三个函数的做用都是改变函数执行时的上下文,即改变函数运行时的this指向。有了这我的生,接下来咱们经过几个例子来学习如何使用这三个函数。
简单说一下三个方法的用法:
1fun.call(thisArg[, arg1[, arg2[, ...]]])
复制代码
它会当即执行函数,第一个参数时指定执行函数中this的上下文,若是不传或者传null、undefined,则表示this指向window,后面的参数是执行函数所需的参数;
1fun.apply(thisArg[, [arg1, arg2, ...]])
复制代码
它会当即执行函数,第一个参数时指定执行函数中this的上下文,若是不传或者传null、undefined,则表示this指向window,第二个参数接收一个数组(这是与call惟一的区别);
1var foo = fun.bind(thisArg[, arg1[, arg2[, ...]]]);
复制代码
它不会当即执行函数,而是返回一个心得函数,这个新的函数被指定了this上下文,接收的参数与call一致;
例7:
1234567891011let person = {
name : 'Heternally'
}
var name = 'window';
function getName() {
console.log(`Hello, my name is ${this.name}`);
}
getName(); // 'Hello, my name is window'
getName.call(person); // 'Hello, my name is Heternally'
getName.apply(person); // 'Hello, my name is Heternally'
getName.bind(person)(); // 'Hello, my name is Heternally'
复制代码
能够看到,使用call、apply、bind方法后,能够动态改变函数执行上下文的this
指向
每当使用new
关键字调用函数时,会自动把this
绑定在新对象上,而后再调用这个函数
例8:
12345678function Person(name) {
this.name = name;
console.log(this);
}
var people = Person('Heternally'); // window
var people1 = new Person('Heternally'); // Person {name: "Heternally"}
people.name; //Cannot read property 'name' of undefined
people1.name; // 'Heternally'
复制代码
在ES6中,新加入了箭头函数,它和普通函数最不一样的一点就是,对于箭头函数的this指向,只须要看它是在哪里建立便可
例9:
123456789101112131415var person = {
name : 'Heternally',
getName1 : function () {
setTimeout(function(){
console.log(this);
},1000)
},
getName2 : function () {
setTimeout(()=>{
console.log(this);
},1000)
}
}
person.getName1(); //window
person.getName2(); // {name:'Heternally',getName1:f,getName2:f}
复制代码
能够看到,在getName2方法的setTimeout函数中,没有跟getName1中setTimeout函数同样打印window,而是打印出person对象。
简单说:箭头函数中的this只和定义它时做用域有关,并不受在哪里及如何调用的影响;
了解了this指向及多种改变this指向的方法后,咱们还须要了解这多种方法的优先级,
1函数直接调用 < 对象方法调用 < call/apply < bind < new < 箭头函数
复制代码
要判断this指向,须要找到是这个函数的直接调用位置,找到以后能够依据以下方法进行判断this的指向: