共计 2880 个字符,预计需要花费 8 分钟才能阅读完成。
以下内容为自己浏览《你不晓得的 Javascript》中 this 局部的读书小结,有趣味的话能够间接看原著。
前言
- 初步理解 this
1.this 不指向函数本身
2.this 不指向函数的词法作用域(箭头函数除外)
3.this 实际上切实函数调用时产生的绑定,它指向什么齐全取决于函数在哪里调用,也就是函数的调用地位。
绑定规定
默认绑定
- 默认绑定中,this 指向全局对象
-
如果判断是否是默认绑定?
察看函数的调用地位,不带任何润饰的函数援用进行调用,实用默认绑定。留神严格模式下,不能将全局对象用于默认绑定,this 会绑定到 undefined。fucntion foo() {console.log(this.a) } var a = 2; foo() // 2
隐式绑定
- 隐式绑定规定会把函数调用中的 this 绑定到这个上下文对象。
-
察看调用地位是否有上下文对象,或者被某个对象领有或者蕴含,如下:
fucntion foo() {console.log(this.a) } var obj = { a: 2, foo: foo } obj.foo() // 2
-
对象属性援用链上只有最初一层在调用地位中起作用。
function foo() {console.log(this.a) } var obj1 = { a: 2, foo: foo } var obj2 = { a: 42, obj1: obj1 } obj2.obj1.foo() //2
-
函数援用导致隐式绑定失落
1. 函数援用
var a = 'global'
function foo() {console.log(this.a)
}
var obj1 = {
a: 2,
foo: foo
}
var bar = obj1.foo
bar() // 'global'
2. 参数传递或者回调函数(实质是隐式赋值)
var a = 'global'
function foo() {console.log(this.a)
}
var obj1 = {
a: 2,
foo: foo
}
var bar = obj1.foo
function bar(fn) {fn()
}
bar(obj1.foo) // 'global'
setTimeout(obj1.foo, 500) //'global'
显式绑定
- call(obj, …args)
- apply(obj, args)
- bind(obj, …args)es5 硬绑定
New 绑定
- 应用 new 来调用函数时,咱们会结构一个新对象并把它绑定到函数调用中的 this 上。
function foo(val) {this.a = val}
let bar = new foo(2)
console.log(bar.a) // 2
// 此时函数中的 this => bar。// 简略理解一下应用 new 来调用函数,会产生什么
// 1.创立(或者说结构)一个全新的对象。// 2.这个新对象会被执行 [[Prototype]] 连贯。// 3.这个新对象会绑定到函数调用的 this。// 4.如果函数没有返回其余对象,那么 new 表达式中的函数调用会主动返回这个新对象。// 也就是在第 3 步的时候才会进行 this 绑定,更体现了 this 绑定是产生在函数调用的时候。
优先级比拟
隐式绑定和默认绑定(不言而喻)
不言而喻,隐式绑定优先级高于默认绑定
显示绑定和隐式绑定
function foo() {console.log(this.name)
}
let obj1 = {
name: 'obj1',
foo
}
let obj2 = {name: 'obj2',}
obj1.foo.call(obj2) // 'obj2'
显式绑定优先级高于隐式绑定
new 绑定和隐式绑定
function foo(name) {this.name = name}
let obj1 = {
name: 'obj1',
foo
}
obj1.foo('new name')
console.log(obj1.name) // new name
var bar = new obj1.foo('bar')
console.log(bar.name) // bar
console.log(obj1.name) // new name
new 绑定优先级高于隐式绑定
new 绑定和显示绑定
-
ES5 中内置的 Function.prototype.bind(..)
function foo(name) {this.name = name} let obj1 = { name: 'obj1', foo } var newFoo = foo.bind(obj1) newFoo('new name') console.log(obj1.name) // new name var bar = new newFoo('bar') console.log(bar.name) // bar console.log(obj1.name) // new name
如和判断 this(个别状况下(非箭头函数),判断流程)
1.函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
2.函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。
3.函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。
4.如果都不是的话,应用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。
(例外:如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值在调用时会被疏忽,理论利用的是默认绑定规定)
箭头函数
1. 箭头函数不应用 this 的四种规范规定,而是依据外层(函数或者全局)作用域来决定 this。
2. 箭头函数的绑定无奈被批改
3. 箭头函数用更常见的词法作用域取代了传统的 this 机制。
4. 在没有箭头函数之前,咱们通常应用 that 或者 self,去代替函数外部的 this
this.a = 'global'
var obj1 = {a: 1}
function foo() {setTimeout_(() => {console.log(this.a)
})
}
function bar() {setTimeout_(function() {console.log(this.a)
})
}
function setTimeout_(fn) {fn()
}
foo.call(obj1) // 1 箭头函数,须要察看箭头函数被创立时的词法作用域,this 取决于外层作用域
bar.call(obj1) // global 一般函数应用四条规定,次要察看函数被调用时的状况
总结
- 如果要判断一个运行中函数的 this 绑定,就须要找到这个函数的间接调用地位。找到之后就能够程序利用上面这四条规定来判断 this 的绑定对象。
1.由 new 调用?绑定到新创建的对象。
2.由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
3.由上下文对象调用?绑定到那个上下文对象。
4.默认:在严格模式下绑定到 undefined,否则绑定到全局对象。肯定要留神,有些调用可能在无心中应用默认绑定规定。 - ES6 中的箭头函数并不会应用四条规范的绑定规定,而是依据以后的词法作用域来决定 this,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。