实在this是一个陈词滥调的问题了。关于this的文章异常多,实在我本以为本身早弄邃晓了它,不过昨天在做项目的过程当中,照样涌现了一丝迷惑,想到也许之前在JavaScript weekly里珍藏待看的一篇详解this的文章(后有链接,也附上了稀土上的中文译文)和另一篇一名先辈引荐的文章,就把它们看了看,对this的熟悉确切提升了一些。
JavaScript 中的’this‘是动态的,它在函数运行时被肯定而非在函数声明时被肯定。一切的函数都能够挪用’this’,这无关于该函数是不是属于某个对象。关于this,主要有以下四种状况。
1.被当作对象的要领被挪用
假如该函数是被当作某一个对象的要领,那末该函数的this指向该对象;
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() // this = john
这里有一点值得注重,当一个对象的要领被取出来赋值给一个变量时,该要领变成函数触发,this指向window或underfind(严厉形式)。
2.函数以内挪用
当函数中有 this
,实在就意味着它被当作要领挪用,之间挪用相当于把他当作window对象的要领,this指向window,值得注重的是ES5现实上是划定这类状况this=undefined
的,只浏览器大多照样根据老的要领实行(本人在最新版的Chrome,Safari,Firefox中测试都指向window(201607)),在火狐下运用严厉形式指向undefined;
func()
function func() {
alert(this) // [object Window] or [object global] or kind of..
}
为了通报this
,()之前应当为援用范例,类似于obj.a
或许 obj['a']
,不能是别的了。
这里还存在一个小坑,当对象的要领中还存在函数时,该函数现实上是当作函数形式触发,所以其this
默以为window(严厉形式下为undefined)解决办法是给该函数绑定this。
var numbers = {
numberA: 5,
numberB: 10,
sum: function() {
console.log(this === numbers); // => true
function calculate() {
// this is window or undefined in strict mode
console.log(this === numbers); // => false
return this.numberA + this.numberB;
}
return calculate();
}
};
numbers.sum(); // => NaN or throws TypeError in strict mode
var numbers = {
numberA: 5,
numberB: 10,
sum: function() {
console.log(this === numbers); // => true
function calculate() {
console.log(this === numbers); // => true
return this.numberA + this.numberB;
}
// use .call() method to modify the context
return calculate.call(this);
}
};
numbers.sum(); // => 15
3.在new
中挪用
一个援用对象的变量现实上保留了对该对象的援用,也就是说变量现实保留的是对实在数据的一个指针。
运用new关键字时this
的转变实在有以下几步:
建立
this = {}
.new实行的过程当中能够转变
this
,然后增加属性和要领;返回被转变的
this
.
function Animal(name) {
this.name = name
this.canWalk = true
}
var animal = new Animal("beastie")
alert(animal.name)
须要注重的是假如组织函数返回一个对象,那末this指向返回的谁人对象;
function Animal() {
this.name = 'Mousie';
this.age = '18';
return {
name: 'Godzilla'
} // <-- will be returned
}
var animal = new Animal()
console.log(animal.name) // Godzilla
console.log(animal.age)//undefined
这里须要注重的是不要遗忘运用new,不然不会建立一个新的函数。而是只是实行了函数,相当于函数挪用,this实在指向window
function Vehicle(type, wheelsCount) {
this.type = type;
this.wheelsCount = wheelsCount;
return this;
}
// Function invocation
var car = Vehicle('Car', 4);
car.type; // => 'Car'
car.wheelsCount // => 4
car === window // => true
4.明白挪用this
,运用call
和apply
这是最具JavaScript特征的处所。
以下代码:
func.call(obj, arg1, arg2,...)
第一个参数将作为this
的指代对象,以后的参数将被作为函数的参数,解决要领是运用bind。
function Animal(type, legs) {
this.type = type;
this.legs = legs;
this.logInfo = function() {
console.log(this === myCat); // => true
console.log('The ' + this.type + ' has ' + this.legs + ' legs');
};
}
var myCat = new Animal('Cat', 4);
// logs "The Cat has 4 legs"
setTimeout(myCat.logInfo.bind(myCat), 1000);
// setTimeout??
var john = {
firstName: "John",
surname: "Smith"
}
function func(a, b) {
alert( this[a] + ' ' + this[b] )
}
func.call(john, 'firstName', 'surname') // "John Smith"
至于apply,其只是以数组的方传入参数,别的部份是一样的,以下:
func.call(john, 'firstName', 'surname')
func.apply(john, ['firstName', 'surname'])
它们也可用于在 ES5 中的类继续中,挪用父级组织器。
function Runner(name) {
console.log(this instanceof Rabbit); // => true
this.name = name;
}
function Rabbit(name, countLegs) {
console.log(this instanceof Rabbit); // => true
// 间接挪用,挪用了父级组织器
Runner.call(this, name);
this.countLegs = countLegs;
}
var myRabbit = new Rabbit('White Rabbit', 4);
myRabbit; // { name: 'White Rabbit', countLegs: 4 }
5..bind()
对照要领 .apply() 和 .call(),它俩都马上实行了函数,而 .bind() 函数返回了一个新要领,绑定了预先指定好的 this ,并能够延后挪用。
.bind() 要领的作用是建立一个新的函数,实行时的上下文环境为 .bind() 通报的第一个参数,它许可建立预先设置好 this 的函数。
var numbers = {
array: [3, 5, 10],
getNumbers: function() {
return this.array;
}
};
// Create a bound function
var boundGetNumbers = numbers.getNumbers.bind(numbers);
boundGetNumbers(); // => [3, 5, 10]
// Extract method from object
var simpleGetNumbers = numbers.getNumbers;
simpleGetNumbers(); // => undefined or throws an error in strict mode
运用.bind()
时应当注重,.bind() 建立了一个永久的上下文链并不可修正。一个绑定函数纵然运用 .call() 或许 .apply()传入其他差别的上下文环境,也不会变动它之前衔接的上下文环境,从新绑定也不会起任何作用。
只要在组织器挪用时,绑定函数能够转变上下文,然而这并非迥殊引荐的做法。
6.箭头函数
箭头函数并不建立它本身实行的上下文,使得 this 取决于它在定义时的外部函数。
箭头函数一次绑定上下文后便不可变动,纵然运用了上下文变动的要领:
var numbers = [1, 2];
(function() {
var get = () => {
console.log(this === numbers); // => true
return this;
};
console.log(this === numbers); // => true
get(); // => [1, 2]
// 箭头函数运用 .apply() 和 .call()
get.call([0]); // => [1, 2]
get.apply([0]); // => [1, 2]
// Bind
get.bind([0])(); // => [1, 2]
}).call(numbers);
这是由于箭头函数具有静态的上下文环境,不会由于差别的挪用而转变。因而不要运用箭头函数定义要领
function Period (hours, minutes) {
this.hours = hours;
this.minutes = minutes;
}
Period.prototype.format = () => {
console.log(this === window); // => true
return this.hours + ' hours and ' + this.minutes + ' minutes';
};
var walkPeriod = new Period(2, 30);
walkPeriod.format(); // => 'undefined hours and undefined minutes'
参考
强烈引荐以为没弄邃晓的同砚看看上面三篇文章,个中第三篇是第二篇的译文。假如人人对this另有疑问,也迎接人人一同议论,交换增进思索,共同进步。