this
并不是指向函数本身this
在任何情况下都不指向函数的词法作用域this
是在运行时进行绑定的, 而并不是在编写时绑定, 它的上下文取决于函数调用时的各种条件this
的绑定和函数声明的位置没有任何关系, 只取决与函数的调用方法
默认绑定
当函数被单独定义和调用的时候, 应用的规则就是绑定全局变量 window
。
function person(){
var weight = 120
console.log(this) // window
console.log(this.weight) // undefied
}
person() // window.person() person 函数绑定在 window 对象上
PS: 这里的 this
对象指的是 window
对象
隐式绑定
函数调用时拥有一个上下文对象, 就好像这个函数是属于该对象的一样, 必须在一个对象内部包含一个指向函数的属性, 并通过这个属性间接引用函数, 从而把 this
间接(隐式)绑定到这个对象上。
var person = {
height: 170,
age: 25,
weight: 120,
eat: function () {
console.log(this.height) // 170
console.log('吃饭')
},
sleep: function () {
console.log(this.weight) // 120
console.log('睡觉')
},
}
person.eat() // window.person.eat()
person.sleep() // window.person.sleep()
PS: 这里的 this
对象指的是 person
对象
显式绑定
使用 bind
、apply
、call
函数, 它接收的第一个参数即是上下文对象并将其赋给 this
。
var person = {
height: 170,
age: 25,
weight: 120,
eat: function () {
console.log(this.height) // 170
console.log('吃饭')
},
sleep: function () {
console.log(this.weight) // 120
console.log('睡觉')
},
}
function test() {
console.log(this.age)
}
test.call(person) // 这里把 person 作为对象传入, 结果为 25
new
绑定
如果是一个构造函数, 那么用 new
来调用, 那么绑定的是新创建的对象。
function person(){
this.weight = 120
console.log(this) // person
console.log(this.weight) // 120
}
var p = new person() // 如果不创建对象, 则 this 为 window 对象
console.log(p.weight) // 120
PS: 这里的 this
对象指的是 person
函数对象
- 当
this
遇到return
function person(){
this.weight = 120
return {} // 返回一个空对象
}
var p = new person()
console.log(p.weight) // undefined
function person(){
this.weight = 120
return function(){} // 返回一个函数
}
var p = new person()
console.log(p.weight) // undefined
function person(){
this.weight = 120
return 1 || undefined || null // 返回一个非函数
}
var p = new person()
console.log(p.weight) // 120
函数的的bind
、call
、apply
方法
- call
call
可以用来调用所有者对象作为参数的方法, 能够使用属于另一个对象的方法。
call
可以接受多个参数, 以 ,
分割。
var person = {
height: 170,
eat: function () {
console.log(this.height) // 170
console.log('吃饭')
},
}
var p = person.eat
p.call(person)
var person = {
height: 170,
eat: function (age, weight) {
console.log(age) // 25
console.log(weight) // 120
console.log(this.height) // 170
console.log('吃饭')
},
}
var p = person.eat
p.call(person, 25, 120)
- apply
apply
方法和 call
方法有些相似, 它也可以改变 this
的指向。
apply
可以接受多个参数, 第二个参数必须是 数组
格式。
var person = {
height: 170,
eat: function () {
console.log(this.height) // 170
console.log('吃饭')
},
}
var p = person.eat
p.apply(person)
var person = {
height: 170,
eat: function (age, weight) {
console.log(age) // 25
console.log(weight) // 120
console.log(this.height) // 170
console.log('吃饭')
},
}
var p = person.eat
p.apply(person, [25, 120])
PS: 如果 call
和 apply
的第一个参数写的是 null
, 那么 this
指向的是 window
对象。
- bind
bind
只有需要调用时才调用, 可以用来改变this
的指向。
bind
可以将参数在执行的时候添加, 也可以开始添加, 也可以拆开来在初始时和执行时分别添加。
bind
可以接受多个参数, 以 ,
分割。
var person = {
height: 170,
eat: function () {
console.log(this.height)
console.log('吃饭')
},
}
var p = person.eat
let bindFunc = p.bind(person) // 操作不执行
console.log(bindFunc)
/*
ƒ () {
console.log(this.height) // 170
console.log('吃饭')
}
*/
// 只有执行 bindFunc 函数才算调用
bindFunc()
var person = {
height: 170,
eat: function (age, weight) {
console.log(age) // 25
console.log(weight) // 120
console.log(this.height) // 170
console.log('吃饭')
},
}
var p = person.eat
let bindFunc = p.bind(person, 25, 120) // 操作不执行
bindFunc()
let bindFunc2 = p.bind(person)
bindFunc2(25, 120)
// 也可以拆开来, 下面参数是相加的
let bindFunc3 = p.bind(person, 25)
bindFunc3(120)
总结:
- 如果返回值是一个对象, 那么
this
指向的就是那个返回的对象, 如果返回值不是一个对象那么this
还是指向函数的实例。 - 还有一点就是虽然
null
也是对象, 但是在这里this
还是指向那个函数的实例, 因为null
比较特殊。