JS 中的 this 对每位前端工程师都不生疏,常常看到对象这里 this 那边 this,那什么是 this?答案就是上下文对象,即被挪用函数所处的环境,也就是说,this 在函数内部指向了挪用函数的对象。
浅显的讲,就是谁挪用了函数。
🐃 状况 1
this 指向 window
var name = 'xiaoming' // 思索,为何不能用 let 或许 const ?
function foo () {
console.log(this.name)
}
foo() // xiaoming
谁挪用了这个函数,答案就是 window。这好明白,由于这里的变量和函数都是直接挂在 window 上的,等同于 window.foo()。需注意,严厉形式下,this 为 undefined
🐏 状况 2
this 指向一个对象
var name = 'xiaoming'
var foo = {
name: 'Jon',
getName () {
console.log(this.name)
}
}
foo.getName() // Jon
谁挪用了这个函数,答案是 foo 对象,所以打印了 Jon 而不是 xiaoming
var bar = foo.getName
bar() // xiaoming
假如赋值到另一个变量,就变成 window 挪用,所以打印了 xiaoming
🐎 状况 3
this 指向了一个用 new 新天生的对象
function Person (name) {
this.name = name
this.getName = function () {
console.log(this.name)
}
}
var jser = new Person('Jon')
jser.getName() // Jon
这类体式格局成为 new 绑定,也叫做组织挪用。
JavaScript 中,new 的机制现实上和面向类的言语完整差别,组织函数只是一些运用 new 操纵符时被挪用的函数,它们并不会属于某个类,也不会实例化一个类。
现实上,除 ES6 的 Symbol()外,一切函数都能够用 new 来挪用,所以并不存在所谓的组织函数,只要关于函数举行组织挪用。
运用 new 来挪用函数,或许说发作组织函数挪用时,会自动实行下面的操纵:
- 建立(或许说组织)一个全新的对象
- 这个新对象会被实行原型链接
- 这个新对象会绑定到函数挪用的 this
- 假如函数没有返回其他对象,那末 new 表达式中的函数挪用会自动返回这个新对象
这个例子中,运用 new 来挪用 Person(..) 时,我们会组织一个新对象(jser)并把它绑定到 Person(..) 挪用中的 this 上。
或许能够这么想,谁挪用了 getName ?就是 jser 挪用了,所以 this 指向了 jser
🦍 状况 4
用 call,apply 和 bind 来修正 this 指向
🍎 call / apply
call 和 apply 是以差别对象作为上下文对象来挪用某个函数,举个例子:
var bar = {
name: 'bar',
getName () {
console.log(this.name)
}
}
var foo = {
name: 'foo'
}
bar.getName.call(foo) // foo
看起来像是借用函数,对象 foo 借用了 bar 的函数 getName,所以我们推断一个对象范例,常常这么搞:
let foo = [1,2,3,4,5]
Object.prototype.toString.call(foo) // "[object Array]"
apply 和 call 的用法一样,差别点在于 call 用参数表给挪用函数传参,而 apply 运用了数组
🍉 bind
bind 能够永久性的修正函数中的 this 的指向,无论谁挪用,this 指向都一样,并返回了完成绑定的函数,看例子:
var bar = {
name: 'bar',
getName () {
console.log(this.name)
}
}
var foo = {
name: 'foo'
}
foo.func = bar.getName.bind(bar)
foo.func() // bar
这里的 func 不受 foo 影响,this 照样指向了 bar
var bar = {
name: 'bar',
getName () {
console.log(this.name)
}
}
func = bar.getName.bind(bar)
func() // bar
这里的 func 也不受 window 影响,this 照样指向了 bar
综合上述,bind 强迫修正了 this,谁挪用了函数 this 都不能被修正
🍒 疏忽 this
假如你把 null 或许 undefined 作为 this 的绑定对象传入 call、apply 或许 bind,这些值再挪用时会被疏忽,现实运用的是默许绑定。
🐆 箭头函数
ES6 中引见了一种没法运用这些划定规矩的特别函数范例:箭头函数,依据外层(函数或许全局)作用域来决议 this,箭头函数常用于回调函数
🐣 状况 1 中,为何不能用 let 声明?
ES6 中,let 敕令、const 敕令、class 敕令声明的全局变量,不属于顶层对象的属性,window 没法访问到。var 敕令和 function 敕令声明的全局变量,属于顶层对象的属性,window 能访问到。
所以 状况 1 中改成:
let name = 'xiaoming'
function foo () {
console.log(this.name)
}
foo() // undefined
🚀 参考
- 《ECMAScript 6 入门》let 和 const 敕令 – 顶层对象的属性 by 阮一峰
- 《【进阶 3-5 期】深度剖析 new 道理及模仿完成》 By 木易杨
- 《你不知道的 JavaScript 上卷》第二部份 第 2 章
- 《Node.js 开辟指南》附录 A