一、this 学习笔记
this 指在调用的时候,属性或方法“当前”所在的对象;或者说点之前的对象
const app = {
init() {
this.$btn = document.querySelector('button')
this.bind()
},
bind() {
this.$btn.onclick = function() {
console.log(this)
this.getData() //这样写对吗,如果不对该如何修改?
}
},
getData() {
console.log('get data...')
}
}
app.init()
2. 如何修改?有哪些写法?
- 第一种修改方法:使用 self
const app = {
init() {
this.$btn = document.querySelector('button')
this.bind()
},
bind() {
let self = this
this.$btn.onclick = function() {
console.log(this) // 这个this 还是 btn 对象
self.getData() //self 代表外面的this,也就是app
}
},
getData() {
console.log('get data...')
}
}
app.init()
- 第二种修改方法:使用箭头函数
const app = {
init() {
this.$btn = document.querySelector('button')
this.bind()
},
bind() {
this.$btn.onclick = () => {
console.log(this) // 在确定this直属的函数时,不考虑箭头函数
this.getData() // 所以当前this直属的函数是bind
}
},
getData() {
console.log('get data...')
}
}
app.init()
3. 通过一些例子加深对 this 的理解
- 例子1: 调用对象中的方法,方法本质是函数
window.name = '网页'
let people = {
name: '掘金',
sayName() {
console.log(this.name)
}
}
let sayAgain = people.sayName // 地址;等价于函数表达式;全局对象
function sayName(){
console.log(this.name)
}
people.sayName()
sayAgain()
sayName()
- 例子2:数组
let arr = []
for(let i=0; i<3; i++){
arr[i] = function() { console.log(this) }
}
arr[0]() // 所属的对象是数组 arr,即 this
let fn = arr[0] // 等价于 let fn = function() { console.log(this) }
fn()
- 例子3:函数嵌套函数
let people = {
name: '掘金',
sayName() {
setTimeout(function(){
console.log(this.name) // this 指向 setTimeout
}, 0)
}
}
people.sayName()
let people = {
name: '掘金',
sayName() {
setTimeout(() => {
console.log(this.name) // this 指向 people,这也是定时器一般用箭头函数的原因。
}, 0)
}
}
people.sayName()
- 例子4:call/apply/bind
let obj = {
fn(a, b) {
console.log(this)
}
}
obj.fn(1, 2) // this 是 obj
//等价于
obj.fn.call(obj, 1, 2)
obj.fn.apply(obj, [1, 2])
obj.fn.bind(obj,1, 2) // bind 方法返回一个新函数,this 指向 bind() 的第一个参数,其余参数作为新函数的参数。
- 例子5:DOM 事件处理函数
let app = {
container: document.querySelector('body'),
init: function(){
//点击的时候会执行 sayHello,sayHello 里面的 this 代表 body 对象
this.container.addEventListener('click', this.sayHello)
// 点击的时候会执行 sayHello,sayHello 里面的 this 代表 app 对象
// bind 方法第一个参数的 this 指向的就是 app
this.container.addEventListener('click', this.sayHello.bind(this))
},
sayHello: function(){
console.log(this)
}
}
app.init()
- 例子6:原型链与构造函数
function Wife(name) {
this.name = name
} // 构造函数,它自身在一个 prototype 属性
Wife.prototype.showSkill = function() {
console.log('我是' + this.name + ', 我的技能是唱歌、跳舞、打游戏')
} // 在构造函数的原型上添加新属性
let wife = new Wife('新桓结衣') // 构造函数是实例的原型,this 指向实例
wife.showSkill() // 会到构造函数的原型中寻找(原型的原型)
- 例子7:严格模式
function f1(){
return this;
}
//在浏览器中:
f1() === window; //在浏览器中,全局对象是window
//在Node中:
f1() === globalThis;
function f2(){
"use strict"; // 这里是严格模式
return this;
}
f2() === undefined; // true
二、拓展知识
1. 方法的定义
从ECMAScript 2015开始,在对象初始器中引入了一种更简短定义方法的语法,这是一种把方法名直接赋给函数的简写方式。
- ECMAScript 2015 之前方法的定义
var obj = {
foo: function() {
/* code */
},
bar: function() {
/* code */
}
};
- ECMAScript 2015 之后方法的定义(简写)
var obj = {
foo() {
/* code */
},
bar() {
/* code */
}
};
2. 对象复习:使用变量作属性名及注意事项
let p = 'name'
let obj = { p: "frank"} // 属性名为 "p1"
let obj = { [p]: "frank"} // 属性名为 "name"
注意事项:obj.p 等价于 obj['p'],不等价于 obj[p],因为 obj.p 中的 p 是字符串,而不是变量。
参考文章
- JavaScript 重难点之一次性弄懂 this、call/apply/bind by 若愚
- this 权威文档 by MDN