场景1:全局环境下的 this
函数在浏览器全局环境中被简单调用,非严格模式下this
指向window
; 在use strict
指明严格模式的情况下就是undefined
const foo = {
bar: 10,
fn: function() {
console.log(this)
console.log(this.bar)
}
}
var fn1 = foo.fn
fn1()
这里this
仍然指向的是window
。虽然fn函数在foo
对象中作为方法被引用,但是在赋值给fn1
之后,fn1
的执行仍然是在window
的全局环境中。因此输出window
和undefined
场景2:上下文对象调用中的 this
const o1 = {
text: 'o1',
fn: function() {
return this.text
}
}
const o2 = {
text: 'o2',
fn: function() {
return o1.fn()
}
}
const o3 = {
text: 'o3',
fn: function() {
var fn = o1.fn
return fn()
}
}
console.log(o1.fn()) //o1
console.log(o2.fn()) //o1
console.log(o3.fn()) //undefined
- 第一个
console
最简单,o1
没有问题。难点在第二个和第三个上面,关键还是看调用this
的那个函数。 - 第二个
console
的o2.fn()
,最终还是调用o1.fn()
,因此答案仍然是o1
。 - 最后一个,在进行
var fn = o1.fn
赋值之后,是“裸奔”调用,因此这里的this
指向window
,答案当然是undefined
。
如果我们需要让:
console.log(o2.fn())
如果不能使用bind/call/apply
,有别的方法吗?
const o1 = {
text: 'o1',
fn: function() {
return this.text
}
}
const o2 = {
text: 'o2',
fn: o1.fn
}
console.log(o2.fn())
this
指向最后调用它的对象,在 fn
执行时,挂到 o2
对象上即可,我们提前进行了类似赋值的操作。
场景3:bind/call/apply
改变 this 指向
let dog = {
name: "汪汪",
sayName() {
console.log('我叫' + this.name);
},
eat(food1, food2) {
console.log(this.name + '喜欢吃' + food1 + '和' + food2);
}
}
let cat = {
name: "喵喵"
}
dog.sayName.call(cat) //call可以调用函数,指定this指向cat
dog.eat.call(cat, "鱼", "肉") //call第一个参数是指定this的指向,后面都是函数传参
dog.eat.apply(cat, ['鱼', '肉']) //apply和call唯一的区别是apply()传入的参数是以数组的形式
let fun = dog.eat.bind(cat, '鱼', '肉')
fun()
//bind和call的区别在于bind不会调用函数,会作为一个返回值返回一个函数,即可以多次调用
场景 4:构造函数和 this
function Foo() {
this.bar = "Lucas"
}
const instance = new Foo()
console.log(instance.bar) //Lucas
new
操作符调用构造函数,具体做了什么?以下供参考:
- 创建一个新的对象;
- 将构造函数的
this
指向这个新对象; - 为这个对象添加属性、方法等;
- 最终返回新对象。
结论:如果构造函数中显式返回一个值,且返回的是一个对象,那么this
就指向这个返回的对象;如果返回的不是一个对象,那么this
仍然指向实例。
场景 5:箭头函数中的 this 指向
箭头函数使用this
不适用以上标准规则,而是根据外层(函数或者全局)上下文作用域来决定。
const foo = {
fn: function () {
setTimeout(function() {
console.log(this)
})
}
}
console.log(foo.fn())
this
出现在 setTimeout()
中的匿名函数里,因此 this
指向 window
对象。如果需要 this
指向 foo
这个 object
对象,可以巧用箭头函数解决:
const foo = {
fn: function () {
setTimeout(() => {
console.log(this)
})
}
}
console.log(foo.fn())
// {fn: ƒ}
网友评论