摘要:至于,其只是以数组的方传入参数,其它部分是一样的,如下它们也可用于在中的类继承中,调用父级构造器。间接调用,调用了父级构造器对比方法和,它俩都立即执行了函数,而函数返回了一个新方法,绑定了预先指定好的,并可以延后调用。
</>复制代码
其实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()传入其他不同的上下文环境,也不会更改它之前连接的上下文环境,重新绑定也不会起任何作用。
只有在构造器调用时,绑定函数可以改变上下文,然而这并不是特别推荐的做法。
箭头函数并不创建它自身执行的上下文,使得 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"
参考
Four scents of "this"
Gentle explanation of "this" keyword in JavaScript
JavaScript This 之谜(译文)
强烈推荐觉得没弄明白的同学看看上面三篇文章,其中第三篇是第二篇的译文。如果大家对this还有疑问,也欢迎大家一起讨论,交流促进思考,共同进步。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/86447.html
摘要:理解的函数基础要搞好深入浅出原型使用原型模型,虽然这经常被当作缺点提及,但是只要善于运用,其实基于原型的继承模型比传统的类继承还要强大。中文指南基本操作指南二继续熟悉的几对方法,包括,,。商业转载请联系作者获得授权,非商业转载请注明出处。 怎样使用 this 因为本人属于伪前端,因此文中只看懂了 8 成左右,希望能够给大家带来帮助....(据说是阿里的前端妹子写的) this 的值到底...
摘要:正在失业中的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。是一种祸害译本文浅谈了在中关于的不好之处。浅谈超时一运维的排查方式。 正在失业中的《课多周刊》(第3期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大的...
摘要:正在失业中的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。是一种祸害译本文浅谈了在中关于的不好之处。浅谈超时一运维的排查方式。 正在失业中的《课多周刊》(第3期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大的...
阅读 1210·2021-11-16 11:45
阅读 3228·2021-10-13 09:40
阅读 822·2019-08-26 13:45
阅读 1311·2019-08-26 13:32
阅读 2271·2019-08-26 13:23
阅读 1015·2019-08-26 12:16
阅读 2908·2019-08-26 11:37
阅读 1845·2019-08-26 10:32
极致性价比!云服务器续费无忧!
Tesla A100/A800、Tesla V100S等多种GPU云主机特惠2折起,不限台数,续费同价。
NVIDIA RTX 40系,高性价比推理显卡,满足AI应用场景需要。
乌兰察布+上海青浦,满足东推西训AI场景需要