函数的this在调用时绑定的,完全取决于函数的调用位置(也就是函数的调用方法)。
全局上下文
非严格模式和严格模式中this都是指向顶层对象(浏览器中是window)
this === window // true
'use strict'
this === window
this.name = '若川'
console.log(this.name) // 若川
函数上下文
1. 普通函数调用模式
其实就是默认绑定。 非严格模式下,指向window;严格模式下,指向undefined或null。
// 非严格模式 var创建变量
var name = 'window'
var doSth = function() {
console.log(this.name)
}
doSth() // window
// 非严格模式 let创建变量
let name = 'window'
let doSth = function() {
console.log(this === window)
console.log(this.name)
}
doSth2() // true, undefined
// 严格模式
'use strict'
var name = 'window'
var doSth = function() {
console.log(typeof this === 'undefined')
console.log(this.name)
}
doSth() // true;报错,因为this是undefined
2.对象中的函数调用模式
var name = 'window'
var doSth = function() {
console.log(this.name)
}
var student = {
name: '若川',
doSth,
other: {
name: 'other',
doSth
}
}
student.doSth() // '若川'
student.other.doSth() // 'other'
// 用call类比分别⬇️
student.doSth.call(student)
student.other.doSth.call(student.other)
当把对象中的函数赋值成一个变量:
var studentDoSth = student.doSth
studentDoSth() // 'window'
// 用call类比⬇️
studentDoSth.call(undefined)
3.构造函数调用模式
function Student(name) {
this.name = name
console.log(this) // { name: '若川' }
// 相当于返回了
// return this
}
使用new操作符,会执行以下⬇️
- 创建了一个全新的对象。
- 这个对象会被执行`[[Prototype]]`(也就是`__proto__`)链接。
- 生成的新对象会绑定到函数调用的`this`。
- 通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
- 如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
new操作符调用时,this指向生成的新对象
new调用时的返回值,如果没有显式返回对象或者函数,才是返回生成的新对象
function Student(name) {
this.name = name
// return function f(){}
// return {}
}
var result = new Student('若川')
console.log(result) // { name: '若川' }
// 如果返回函数f,则result是函数f;如果是对象{},则result是对象{}
4.原型链中的调用模式
function Student(name) {
this.name = name
}
var s1 = new Student('若川')
Student.prototype.doSth = function() {
console.log(this.name)
}
s1.doSth() // '若川'
5.箭头函数调用模式
箭头函数与普通函数的区别:
(1) 没有自己的this、super、arguments和new.target绑定
(2) 不能使用new调用
(3) 没有原型对象
(4) 不可以改变this的绑定
(5) 形参名称不能重复
箭头函数中没有this绑定,必须通过查找作用链来决定其值。 如果箭头函数被非箭头函数包含,则this绑定的是最近一层非箭头函数的this,否则this的值被设置为全局对象。
var name = 'window'
var student = {
name: '若川',
doSth: function() {
// var self = this
var arrowDoSth = () => {
// console.log(self.name)
console.log(this.name)
}
arrowDoSth()
},
arrowDoSth2: () => {
console.log(this.name)
}
}
student.doSth() // '若川'
student.arrowDoSth2() // 'window'
如果没有普通函数,则是全剧对象(浏览器则是window)。
无法通过call、apply、bind绑定缓存箭头函数的this(它自身没有this)。
优先级
var name = 'window'
var person = {
name: 'person'
}
var doSth = function() {
console.log(this.name)
return function() {
console.log('return:', this.name)
}
}
var Student = {
name: '若川',
doSth
}
// 普通函数调用
doSth() // window
// 对象上的函数调用
Student.doSth() // '若川'
// call、apply调用
Student.doSth.call(person) //'person'
new Student.doSth.call(person)
new 调用 > call、apply、bind调用 > 对象上的函数调用 > 普通函数调用