参考:https://mp.weixin.qq.com/s/b_SojysoGA_Z7WLJrilizg
一、原理
js函数中的this变量指向是什么?这和this所在的函数的声明和调用情况有关
1. 函数作为对象的属性被调用
作为哪个对象的函数调用的,函数中的this就指向哪个对象。如果在全局环境中调用,this指向window(strict模式时候是undefined)
2. 通过call、apply调用
call和apply都是Function.prototype上的方法。
call和apply可以改变this指向。
当函数调用call()和apply()时,函数都会立即执行。 call和apply的第一个参数都是要绑定的对象。call方法可以传给该函数的参数分别作为自己的多个参数,而apply方法必须将传给该函数的参数合并成一个数组作为自己的一个参数:
const person = {name: 'Sam'};function log(a, b) {console.log(this.name, a, b);}log.call(person, 1, 2); // Sam 1 2log.apply(person, [1, 2]); // Sam 1 2
3. bind绑定后的函数
bind可以将函数的this绑定到指定对象,优先级高于call、apply。
bind后返回一个新的函数。
bind时候还可以传入固定参数。
const person = {name: 'Sam'};function log(a, b) {console.log(this.name, a, b);}const log1 = log.bind(person, 1, 2);log1(); // Sam 1 2
4. 使用new调用(当做构造函数调用)
如果函数被当做构造函数调用,函数中的this指向的是实例。优先级高于bind
5. 箭头函数
箭头函数中的this指向的是它声明时候所在的函数的this。如果在全局声明,那this指向window。
箭头函数的优先级最高,使用call或者apply不会改变指向,使用bind的话,也不会改变this指向,但是bind指定的参数会传给函数。
二、题目
function showThis () {console.log(this)}function showStrictThis () {'use strict'console.log(this)}showThis() // windowshowStrictThis() // undefined
var boss = {name: 'boss',returnThis () {return this}}boss.returnThis() === boss // true
var boss1 = {name: 'boss1',returnThis () {return this}}var boss2 = {name: 'boss2',returnThis () {return boss1.returnThis()}}var boss3 = {name: 'boss3',returnThis () {var returnThis = boss1.returnThisreturn returnThis()}}boss1.returnThis() // boss1boss2.returnThis() // boss1boss3.returnThis() // window
var boss1 = {name: 'boss1',returnThis () {return this}}var boss2 = {name: 'boss2',returnThis: boss1.returnThis}boss2.returnThis() //boss2
function returnThis () {return this}var boss1 = { name: 'boss1' }returnThis() // windowreturnThis.call(boss1) // boss1returnThis.apply(boss1) // boss1
function returnThis () {return this}var boss1 = { name: 'boss1'}var boss1returnThis = returnThis.bind(boss1)boss1returnThis() // boss1var boss2 = { name: 'boss2' }boss1returnThis.call(boss2) // still boss1
function showThis () {console.log(this)}showThis() // windownew showThis() // showThisvar boss1 = { name: 'boss1' }showThis.call(boss1) // boss1new showThis.call(boss1) // TypeError call is not a constructor call不能被用作构造函数var boss1showThis = showThis.bind(boss1)boss1showThis() // boss1new boss1showThis() // showThis
function callback (cb) {cb()}callback(() => { console.log(this) }) // windowvar boss1 = {name: 'boss1',callback: callback,callback2 () {callback(() => { console.log(this) })}}boss1.callback(() => { console.log(this) }) // still windowboss1.callback2() // boss1
var returnThis = () => thisreturnThis() // windownew returnThis() // TypeErrorvar boss1 = {name: 'boss1',returnThis () {var func = () => thisreturn func()}}returnThis.call(boss1) // still windowvar boss1returnThis = returnThis.bind(boss1)boss1returnThis() // still windowboss1.returnThis() // boss1var boss2 = {name: 'boss2',returnThis: boss1.returnThis}boss2.returnThis() // boss2
