看了《你不知道的js》中this这一章,觉得有必要自己记录总结一下,不然过段时间,可能又忘了。
每个函数的this是在调用时被绑定的,完全取决与函数的调用位置。
(1)首先了解一些基础知识:
什么是调用位置呢?
函数被调用的位置。
什么是调用栈?
到达当前执行位置所调用的所有函数。
function baz() {
//当前调用栈是baz,因此当前调用位置是全局作用域
console.log('baz')
bar()
}
function bar() {
//当前调用栈是baz-》bar,因此当前调用位置在baz中
console.log('bar')
foo()
}
function foo() {
//当前调用栈是baz-》bar-》foo,因此当前调用位置在bar中
console.log('foo')
}
baz()//baz的调用位置
(2)this 的四种绑定规则
1、默认绑定
var a = 2;//此时的a就是全局变量,在全局下就能找到a
function foo() {
console.log(this.a)//this指向全局对象
}
foo()// foo 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定。
2、隐式绑定
相当于是调用位置有上下文对象,看例子:
console.log(this)//指向window
function foo() {
console.log(this)//{ a: 2, foo: [Function: foo] }
console.log(this.a)//2
}
var obj = {
a: 2,
foo: foo
}
obj.foo()//2 调用位置会使用obj上下文来引用函数
console.log(this.a)//2
console.log(this)//指向window
//调用foo时,this被绑定到obj,因此this.a与obj.a 一样
隐式丢失:被隐式绑定的函数会丢失绑定对象
function foo() {
console.log(this.a)
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo//函数别名
var a = 'hello.dino'
bar()//bar 引用了foo函数本身,因此此时的bar是一个不带任何修饰的函数调用,因此应用了默认绑定
值得注意的是:setTimeout和函数别名起到一样的作用
3、显式绑定
function foo() {
console.log(this.a)
}
var obj = {
a: 2
}
foo.call(obj)//相当于强制把obj绑定给foo的this
call,applay,bind都是用于硬式绑定this的,另外硬绑定的函数,不可能在修改他的this
如果传入call(null/undefined)硬式绑定会变成默认绑定规则
另外再来一个api调用的上下文
function foo(el) {
console.log(el, this.id)
}
var obj = {
id: 'awesome'
}
var arr = [1, 2, 3]
arr.forEach(foo, obj)
/*1 'awesome'
2 'awesome'
3 'awesome'*/
//调用foo时把this绑定到obj,这里的obj就是foreach这类新的内置函数提供的可选参数放置的上下文,作用和bind的一样
4、new绑定
function foo(a) {
this.a=a
}
var bar=new foo(2)
console.log(bar.a)
总结一下this规则
1、函数是否在new中调用?如果是的话,this绑定的是新创建的对象。
var bar=new foo()
2、是否通过call,apply,bind ,如果是的话,this绑定的是指定的对象。
var bar=foo.call(obj2)
3、函数是否在某个上下文对象中调用
var bar=obj1.foo()
4、如果都不是的话,使用默认绑定。指向全局对象。
var bar=foo()
最后,箭头函数和普通函数有什么区别呢!
内容太多,,我需要消化一下再来
网友评论