hello,大家好呀这里是X,中秋节刚过去,现在又回到认真工作的状态中,最近也结束了答辩,比较放松休闲一些,一周至少一篇的typescript这就来了,这次是对“this”问题产生自己的想法和观点,喜欢的朋友可以点赞收藏,那么你对这个this了解到底有多深呢?
以下的很多一些观点和知识来自我学习的笔记和网络,共同学习进步🥂
学习如何在JavaScript里正确使用this就好比一场成年礼。 由于TypeScript是JavaScript的超集,TypeScript程序员也需要弄清this工作机制并且当有bug的时候能够找出错误所在。 幸运的是,TypeScript能通知你错误地使用了this的地方。 🎈
JavaScript里,this的值在函数被调用的时候才会指定。 这是个既强大又灵活的特点,但是你需要花点时间弄清楚函数调用的上下文是什么。 但众所周知,这不是一件很简单的事,尤其是在返回一个函数或将函数当做参数传递的时候
来个例子:
let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
return function() {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
alert("card: " + pickedCard.card + " of " + pickedCard.suit);
可以看到createCardPicker是个函数,并且它又返回了一个函数。 如果我们尝试运行这个程序,会发现它并没有弹出对话框而是报错了。 因为createCardPicker返回的函数里的this被设置成了window而不是deck对象。 因为我们只是独立的调用了cardPicker()。 顶级的非方法式调用会将this视为window。 (注意:在严格模式下,this为undefined而不是window)。
那么我们该如何解决这个问题呢?
为了解决这个问题,我们可以在函数被返回时就绑好正确的this。 这样的话,无论之后怎么使用它,都会引用绑定的‘deck’对象。 我们需要改变函数表达式来使用ECMAScript 6箭头语法。 箭头函数能保存函数创建时的this值,而不是调用时的值,再来看看修改之后的效果
不幸的是,this.suits[pickedSuit]的类型依旧为any。 这是因为this来自对象字面量里的函数表达式。 修改的方法是,提供一个显式的this参数。 this参数是个假的参数,它出现在参数列表的最前面:
想要直接绑定Desk对象,而不是window或者undefined,可以直接这样玩:
let deck3: Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
// NOTE: The function now explicitly specifies that its callee must be of type Deck
createCardPicker: function(this: Deck) {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
console.log("deck3:"+this.suits);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
可以看到在定义函数的时候,function里的参数为this:Desk,这样子话是不是非常好理解呢😎
它的效果和上面的箭头函数效果一致,这里做了一个简单的测试:
测试代码如下
interface Card {
suit: string;
card: number;
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;
}
let deck2:Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
// NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
console.log("deck2:"+this.suits);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let deck3: Deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
// NOTE: The function now explicitly specifies that its callee must be of type Deck
createCardPicker: function(this: Deck) {
return () => {
let pickedCard = Math.floor(Math.random() * 52);
let pickedSuit = Math.floor(pickedCard / 13);
console.log("deck3:"+this.suits);
return {suit: this.suits[pickedSuit], card: pickedCard % 13};
}
}
}
let cardPicker2 = deck2.createCardPicker();
let pickedCard2 = cardPicker2();
let cardPicker3 = deck3.createCardPicker();
let pickedCard3 = cardPicker3();
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);
console.log("card: " + pickedCard3.card + " of " + pickedCard3.suit);