一、理解this绑定
- 函数在调用时,JavaScript会默认给函数绑定一个this
- this的绑定和定义的位置(编写的位置)无关
- this的绑定和调用方式以及调用的位置有关
- this是在运行时绑定的
- 优先级:new > bind > apply/call > 隐式绑定 > 默认绑定
二、this的绑定规则
- 默认绑定
// 具名函数调用
fucniton foo(){
console.log('foo',this)
}
foo() // this指向window
// 匿名函数调用
// const foo = function(){
// console.log('foo', this)
// }
// foo() // this指向window
- 隐式绑定
// 隐式绑定
const info = {
name: '张三',
age: 24,
sayName() {
console.log('this指向', this)
}
}
info.sayName() // this指向 {name: '张三', age: 24, sayName: ƒ}
- 显示绑定
function foo(name,age) {
console.log('参数', name, age)
console.log('foo被调用时this的指向', this)
}
// apply
// 第一个参数:绑定this
// 第二个参数:已数组形式的实参
// foo.apply('apply', ['张三', 24])
// 参数 张三 24
// this的指向.js:20 foo被调用时this的指向 String {'apply'}
// call
// 第一个参数:绑定this
// 第二个参数:以逗号隔开的参数序列
// foo.call('call', '张三', 24)
// 参数 张三 24
// foo被调用时this的指向 String {'call'}
// bind
// 第一个参数:绑定this
// 第二个参数:以逗号隔开的参数序列
// const changethis = foo.bind('bind', '张佳佳', 24)
// changethis()
// 参数 张佳佳 24
// foo被调用时this的指向 String {'bind'}
// 显示绑定的特殊情况 当apply、call、bind第一个参数为null或者undefined时,this指向window
function foo() {
console.log('this', this)
}
// const bindFoo = foo.bind(null)
// bindFoo() // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
// const bindFoo = foo.bind(undefined)
// bindFoo() // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
foo.apply(null) // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
foo.apply(undefined) // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
foo.call(null) // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
foo.call(undefined) // this Window {window: Window, self: Window, document: document, name: '', location: Location, …}
- 内置函数this绑定
setTimeout(() => {
console.log('settimeout', this) // this指向window
}, 1000);
const btn = document.querySelector("#btn")
btn.onclick = function() {
console.log('onclick', this) // this指向btn元素
}
btn.addEventListener('click', function() {
console.log('addEventListener', this) // this指向btn元素
})
['abc', 'cba'].forEach(element => {
console.log('forEach', this) // this指向window
});
5、new绑定this
function Foo () {
this.name = 'zjj'
this.age = 24
console.log(this) // Foo {name: 'zjj', age: 24}
}
const foo = new Foo()
console.log(foo) // Foo {name: 'zjj', age: 24}
三、this绑定优先级
1、默认绑定的优先级最低
2、显示绑定高于隐式绑定
function foo() {
console.log('this指向', this)
}
const info = {
name: '张三',
age: 24,
foo
}
const obj = { name: '显示绑定' }
info.foo.apply(obj) // this指向 {name: 'apply显示绑定'}
info.foo.call(obj) // this指向 {name: 'call显示绑定'}
const newFun = info.foo.bind(obj)
newFun() // this指向 {name: 'bind显示绑定'}
3、new绑定高于隐式绑定
- new 操作符做了什么?
- 在内存中创建一个新对象。
- 这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype 属性。
- 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。
- 执行构造函数内部的代码(给新对象添加属性)。
- 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
4、new绑定高于bind显示绑定
- new绑定不能和apply和call一起使用所以不存在谁的优先级高的问题
- new绑定高于bind显式绑定
function foo() {
console.log('this指向', this)
}
const obj = {
name: '张三'
}
const bindFun = foo.bind(obj)
bindFun() // this指向 {name: '张三'}
new bindFun() // this指向 foo {}
5、bind绑定优先级高于apply和call
// bind和apply/call的优先级
function foo() {
console.log('this', this)
}
const obj = { name: '张三' }
const bindFoo = foo.bind(obj)
bindFoo() //this {name: '张三'}
bindFoo.apply('apply') // this {name: '张三'}
bindFoo.call('call') // this {name: '张三'}