携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情
this
JavaScript 中的this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。 一起来看一下javascript中this的各种情况吧。
一定不要看在哪里定义,只要看将来在哪里,如何被调用。
对象调用函数
let obj = {
name: 'Tom',
sayHi: function(){
console.log(`${this.name} say hi.`);
}
};
obj.sayHi();
this指向 .前的对象。
var fun1 = obj.sayHi();
fun1();
fun1中的this指向window。
例子:
document.getElementById 这个方法名实在有点过长,我们大概尝试过用一个短的函数来代替它,比如:
var getId = document.getElementById;
getId("#app");
在浏览器中执行过后就会发现,这段代码抛出了一个异常。这是因为许多引擎的document.getElementById 方法的内部实现中需要用到this。这个this 本来被期望指向document,当getElementById 方法作为document 对象的属性被调用时,方法内部的this 确实是指向document 的。
var getId = document.getElementById.bind(document);
var div = getId('app');
console.log(div.id) // 输出: div1
构造函数中
new Constructor(...)
this指向 new正在创建的新对象。
function Person(name){
this.name = name;
}
let p1 = new Person("Tom");
console.log(p1);
function Person(name){
this.name = name;
}
let p1 = new Person
console.log(p1);
但用new 调用构造器时,还要注意一个问题,如果构造器显式地返回了一个object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的this:
var MyClass = function(){
this.name = 'sven';
return { // 显式地返回一个对象
name: 'anne'
}
};
var obj = new MyClass();
alert ( obj.name ); // 输出:anne
如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题:
var MyClass = function(){
this.name = 'sven'
return 'anne'; // 返回string 类型
};
var obj = new MyClass();
alert ( obj.name ); // 输出:sven
对象原型上的函数
Constructor.prototype.fun = function(){}
原型对象中的方法,都是"子对象.fun()" 方式调用,所以,this指向调用这个func函数.前的子对象。
func(),匿名函数自调,回调
func();
(function(){ this... })(...);
arr.forEach(function(){ this ... });
上三种情况this都指向window,严格模式下,指向undefined。
element.onclick = function(){...}
或者:
element.addEventListener("click", function(){...});
DOM事件处理函数里的this指向当前发出事件的.前的DOM元素。
这里可以改成箭头函数吗?
肯定不能:一旦改成箭头函数,this指向外层的window。功能就会出错。
window.id = 'window';
document.querySelector("#app").onclick = function(){
console.log(this.id);
var callback = function() {
console.log(this.id);
}
callback();
};
改为:
window.id = 'window';
document.querySelector("#app").onclick = function(){
console.log(this.id);
var that = this;
var callback = function() {
console.log(that.id);
}
callback();
};
window.id = 'window';
document.querySelector("#app").onclick = function(){
console.log(this.id);
var callback = () => {
console.log(this.id);
}
callback();
};
Vue中this默认都指向当前Vue组件实例对象
<button @click="func"></button>
export default {
methods:{
func(e){
}
}
}
如果想获得click事件触发的DOM元素,可以使用 e.target。
Vue3中使用composition API 去尽量避免使用this。
React中的this
没箭头函数,有了箭头函数之后:
import React, { Component } from 'react';
import store from '../redux';
export default class ReduxPage extends Component {
constructor(props){
super(props);
// this.addBtnClick.bind(this);
}
// 早期
// addBtnClick = function(){
// store.dispatch({
// type: 'ADD',
// payload: 2
// });
// }
addBtnClick = ()=>{
store.dispatch({
type: 'ADD',
payload: 2
});
}
componentDidMount(){
store.subscribe(() => {
this.forceUpdate();
});
}
render() {
const { count } = store.getState().counter;
return (
<div>
<div>
<span>{count}</span>
<button onClick={ this.addBtnClick }>增加</button>
</div>
</div>
)
}
}
import logo from './logo.svg';
import './App.css';
import ReduxPage from './components/ReduxPage';
function App() {
return (
<div className="App">
<ReduxPage/>
</div>
);
}
export default App;
React中函数式组件,并没有组件实例this,去掉this的困惑。
箭头函数中的this
箭头函数中的this,指向函数之外最近的作用域中的this。
几乎所有的匿名函数都可以使用箭头函数来简化;箭头函数是对大多数匿名函数的简写。
// var log = function(msg) {
// console.log(msg, this);
// }
var log = (msg) =>{
console.log(msg, this);
}
log('呵呵');
let obj = {
name: 'Tom',
sayHi: function() {
console.log(`${this.name} say hi.`);
}
};
obj.sayHi();
// 下面name为空
let obj = {
name: 'Tom',
sayHi: () => {
console.log(`${this.name} say hi.`);
}
};
obj.sayHi();
箭头函数,对象的 { } 不是作用域,所以sayHi内的this会指向window。
总结:
- 函数中不包含this,或者希望函数内的this和外部this保持一致,可以改为箭头函数;
- 不希望函数内的this与函数外的this保持一致,都不能改为箭头函数;
刚才说过对象中的方法就不能改为箭头函数:
let obj = {
name: 'Tom',
sayHi() {
console.log(`${this.name} say hi.`);
}
};
既没有function,也没有 =》,只是简写,不影响this指向。
let obj = {
name: 'Tom2',
friends: ["Jerry", "Kate"],
sayHi() {
this.friends.forEach((item) => {
console.log(`${this.name} say hi to ${item}`);
});
}
};
obj.sayHi();
问题:
箭头函数没有作用域,或箭头函数不是作用域? ×
- 箭头函数只是让this指向外部作用域的this;
- 箭头函数内的局部变量,仅再函数内可用,所以箭头函数是有作用域的,影响的只是this;
箭头函数底层相当于.bind(),永久绑定外部this。所以,call无法替换箭头函数中的this。
call, apply,bind
使用call,apply和bind可用改变函数中的this指向。
被bind永久绑定的this,即使使用call,也无法再替换为其他对象了。