this 决定在于函式如何被呼叫
Why use This
可用不同物件,调用同函式使 API 更简洁且易于复用function identify() { console.log(this.name) }let me = { name: "Tom" }let you = { name: "Mark" }identify.call(me) // Tomidentify.call(you) // Mark
影响 this 的情境
默认绑定 => 指向 global 物件
纯粹的调用、直接呼叫Function严格模式("use strict") => 指向 undefined // 浏览器的 global物件 window console.log(this) // window // 浏览器的 global物件 window function test(){ console.log(this) } test()
隐式绑定 => 指向 上下文 物件
物件 => 指向 物件隐式绑定丢失: 函式调用的时候,无上下文,只是对函式的引用 const obj = { test(){ console.log(this) } } const bar = obj.test // 等同于此 const bar = test(){ console.log(this) } bar() // window
new 绑定 ( new建构式 )
new 关键字会作
建立新物件连接 Prototypethis 绑定至该新物件 (相当于物件绑定) const name = '全域' const callMethod = function () { this.name = 'Mark' console.log(this.name) } const myName = new callMethod() console.log(myName.name) // Mark
DOM 物件
this 指向 挂载事件的元件 e.currentTarget const parent = document.querySelector('.parent') parent.addEventListener('click', test) function test(e) { // e.target 指向触发事件的元件 .child console.log('e.target',e.target); // e.currentTarget 指向挂载事件的元件 .parent console.log('e.currentTarget',e.currentTarget); // this 指向挂载事件的元件 .parent 即 e.currentTarget console.log('this',this); }
显式绑定 => 强制绑向目标
bind / apply / call => 指向 目标箭头函式
箭头函式 => 指向 上一个非箭头函式的 this因箭头函式不会产生this,而会照 Scope Chain 向上找箭头函式不可当建构式
闭包的this
纯粹的调用 => window const name = '全域'; function callMethod() { const name = '区域' console.log(this.name) // '全域' return function () { // 闭包 const name = '区域的内层变数' console.log(this.name) // '全域' } } // 分两段 callMethod() 回传内部函式 // 内部函式() 执行,其环境在 window callMethod()()
Object & ArrowFunction
缩写与否 效果一样ArrowFunction 指向上一个非箭头函式的This const name = '全域' const object = { name: 'Object 区域', callMethod: function () { const name = '区域' console.log(this.name) // 区域 (指向物件) }, abbCallMethod () { const name = '缩写函式区域' console.log(this.name) // 区域 (指向物件) }, arrowCallMethod: () => { const name = '箭头函式区域' console.log(this.name) // 全域 }, } object.callMethod() object.abbCallMethod() // 指向上一个非箭头函式的This 此时为 window object.arrowCallMethod()
物件内的闭包
const name = '全域' const object = { name: 'Object 区域', callMethod: function () { const name = '区域' return function () { console.log(this.name) // '全域' } }, callMethod2: function () { const name = '区域' const that = this return function () { console.log(that.name) // '区域' } } } // 分解成 object.callMethod() 得到 Function // 该 Function 则在 window 的环境下执行 object.callMethod()() // that 指向 object 并保存在闭包中 // 执行内部函式,找不到本层that向上找至 callMethod2中的that object.callMethod2()()
题目练习
const obj = { a(){ function b(){ console.log(this); } b(); }}obj.a(); // window (执行环境为 window)
const obj = { a(){ console.log(this) }}// 物件调用该Function执行obj.a() // objconst b = obj.ab() // 直接执行、window
function a(){ console.log(this) }const obj = {}obj.a = aobj.a() // obj
const obj = { a() { console.log(this) // obj function b() { console.log(this) // window } b() // 直接执行的 }}obj.a()
function a(){ console.log(this) // e.currentTarget}const obj = {a}btn.addEventListener('click', obj.a)
function a(){ console.log(this) // window}const obj = { b(){ // a 函式属于直接执行 return function (){ a() } }}btn.addEventListener('click', obj.b())
const obj = { b(){ // e.currentTarget return function (){ console.log(this) } }}// obj.b() 等同于 console.log(this)btn.addEventListener('click', obj.b())
// e.currentTargetfunction a() { console.log(this) }const obj = { b(){ return a } }btn.addEventListener('click', obj.b())
箭头函式题目
const a = () => { // this会去找外层的this console.log(this) // window}btn.addEventListener('click', a)
const obj = { a: () => { // window console.log(this) }}obj.a()
function a() { const b = () => { console.log(this) // window } b() // 直接执行}btn.addEventListener('click', a)
此题重要
function a() { // 此this作为 DOM事件监听因此为 e.currentTarget console.log(this) const b = () => { // 箭头函式不产this 指向外层 e.currentTarget console.log(this) } b() // 直接执行}btn.addEventListener('click', a)
参考资料
六角 This
OBKoro1's Blog
Kanboo
直播学程式