- 函数在调用时,JavaScripts会默认给this绑定一个值;
- this的绑定和定义的位置无关;
- this的绑定和调用方式以及调用的位置有关;
- this是在运行时被绑定的;
this的绑定方式:
- 默认绑定:通过函数进行调用,是独立函数,则this指向全局(global/window)
- 隐式绑定:通过方法进行调用,则this绑定到了所调用的对象上
- 显示绑定:可以指定绑定对象(bind call apply)
- 箭头函数(Arrow Function)
- 构造函数(new)
默认绑定
function foo() {
console.log(this)
}
foo()//window
隐式绑定
var obj = {
name: "obj",
foo: foo
}
function foo() {
console.log(this)
}
obj.foo()//obj
foo()绑定在obj对象上,this指向obj
Example Code 1
function app(){
console.log(this)
this.appVaribale = 'hello'
}
app() //Window
console.log(appVaribale) //hello
console.log(app.appVaribale) //underfind ,appVaribale绑定到了window上
console.log(this) //window
调用app函数时,this指向window,运行 console.log(appVaribale)
代码时window增加了appVaribale对象,且值为 “hello”。与app函数无关,所以运行 console.log(app.appVaribale)
这行代码时JS引擎在app函数里面找不到appVaribale对象,则返回 undefined
。
显示绑定
bind:
function.bind(thisArg[, arg1[, arg2[, ...]]])
call:
function*.call(thisArg, arg1, arg2, ...)
apply:
func*.apply(thisArg, [argsArray])
apply/call/bind: 当传入 null/undefined 时,自动将 this 绑定成全局对象
function add(c, d) {
console.log(this.a + this.b + c + d);
}
var num = {a: 1, b: 3};
add.call(num, 5, 7); // 16
add.apply(num, [10, 20]); // 34
add.call(undefined, 5, 7); // 16
add.apply(null, [10, 20]); // 34
箭头函数
箭头函数没有自己的this,都是从ParentScope继承的
var title = "window"
const video = {
title: 'a',
play: function() {
return () => {
console.log(this.title)
}
}
};
var fn1 = video.play();
fn1()//a
var fn2 = video.play;
fn2()()//window
- 调用video.play函数赋值给了fn1,fn1是一个箭头函数
() => { console.log(this.title) }
,这个箭头函数的this是从ParentScope 处继承来的,video.tilte = “a”。 - 引用video.plya函数,fn2是一个匿名函数调用后返回一个箭头函数
() { return () => { console.log(this.title) } }
,调用箭头函数后,this指向window,因为它从上层作用域 play 继承了this。
构造函数(new)
this 被绑定到正在构造的新对象
function Video(title) {
console.log(this)
this.title = title
}
var video = new Video("a")
绑定优先级
new绑定 > 显示绑定(bind()>call() / apply()) > 隐式绑定(obj.foo()) >默认绑定(独立函数调用)
练习题
习题来自于: 跟着coderwhy学习JavaScript高级(四) - 掘金 (juejin.cn)
var name = "window"
var person = {
name: "person",
sayName: function () {
console.log(this.name)
}
};
function sayName() {
var sss = person.sayName;
sss() //window
person.sayName(); //person
(person.sayName)(); //My Mistake === person.sayName();
(b = person.sayName)(); //window
}
sayName()
sss()
:person.sayName
为function () {console.log(this.name)}
赋值给 sss ,当调用 sss 函数时, 相当于函数独立调用(默认绑定), 指向windowperson.sayName()
: 通过person调用(隐式绑定)(person.sayName)()
: 等价于person.sayName()
,与sss()
不同的是,person.sayName
赋值给了新的变量sss
.(b = person.sayName)()
: 等价于sss()
var name = "window"
var person1 = {
name: "person1",
foo1: function () {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function() {
return function() {
console.log(this.name)
}
},
foo4: function() {
return () => {
console.log(this.name)
}
}
};
var person2 = {name: 'person2'}
person1.foo1(); //person1
person1.foo1.call(person2) //person2
person1.foo2(); //window,上层作用域是全局
person1.foo2.call(person2) //window foo2为箭头函数优先级>call/bind/apply
person1.foo3()(); //window独立函数调用,(person.foo3())()
person1.foo3.call(person2)() //window
person1.foo3().call(person2) //person2
person1.foo4()(); //person1,返回的箭头函数指向上层foo4函数指向person1
person1.foo4.call(person2)() //person2
person1.foo4().call(person2) //person1
person1.foo1()
: 隐式绑定person1.foo1.call(person2)
: 显示绑定, 通过 call() 绑定到了person2上
person1.foo2()
: 箭头函数要注意, 箭头函数本身没有 this 值, this值是从上层作用域(parentScope)继承而来的, foo2的上层作用域是window.
💡 注意person1 是一个对象而非函数, 所以foo2 的上层作用域不是person1
person1.foo2.call(person2)
: 箭头函数优先级 > 显示绑定( call/bind/apply )
person1.foo3()()
: 等价于(person1.foo3())()
, 独立函数调用(默认绑定)
person1.foo3.call(person2)()
: 等价于 (person1.foo3.call(person2))()
, 独立函数调用(默认绑定)person1.foo3().call(person2)
: 最后调用的函数绑定到了person2(显示绑定)
person1.foo4()()
: 返回的箭头函数指向上层 foo4 函数指向person1
person1.foo4.call(person2)()
: 返回的箭头函数指向上层foo4函数指向person2
person1.foo4().call(person2)
: 返回的箭头函数指向上层foo4函数指向person1
💡 箭头函数自身没有 this 值, this值是从上层作用域(parentScope)继承而来的
var name = 'window'
function Person(name) {
this.name = name;
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() //window
person1.obj.foo1.call(person2)() //window
person1.obj.foo1().call(person2) //person2
person1.obj.foo2()() //obj
person1.obj.foo2.call(person2)() //person2
person1.obj.foo2().call(person2) //obj
person1.obj.foo1()()
: 独立函数(默认绑定)person1.obj.foo1.call(person2)()
: 相当于(person1.obj.foo1.call(person2))()
也是独立函数person1.obj.foo1().call(person2)
: 显示绑定, 绑定到了person2 上person1.obj.foo2()()
: 相当于(person1.obj.foo2())()
, 返回了一个箭头函数后调用它, 箭头函数的 this 继承于上层作用域 foo2 .person1.obj.foo2.call(person2)()
: 与person1.obj.foo2()()
类似, 但上层作用域 foo2 的this 被绑定到了 person1 上.person1.obj.foo2().call(person2)
: 返回的箭头函数指向上层 foo2 的 this 指向person2