JavaScript中的this

152 阅读3分钟

1.基本阐述

  • this就是执行时确定的
function func() {
    /*
    executionContext = {
        this: {}   // context执行上下文中,指定this,指向函数当前的上下文
    }
    */
    console.log('this::', this)   
   
}
 //全局(global 或者 Window)或 者undefined(严格模式)
func();

2. 五种场景

2.1 函数直接调用时(自然执行就是全局)

function func() {
    console.log('this::', this)
}

function outer() {
    func();
}

outer();

// 自然执行时,就是全局或undefined(严格模式)
// outer自然执行(不被访问操作符访问,不被点出来(a.outer())),不会向外找
// 不在对象上

2.2 函数被对象调用(执行时谁点出来的就是谁)

  • 简单调用
var teacher = {
    buybuybuy: function () {
        console.log('this::', this)
    }
};

teacher.buybuybuy();
 // this:: { buybuybuy: [Function: buybuybuy] }
 // this就是调用该函数的对象
  • 复杂调用
var teacher = {
    name: 'teacher',
    hand: {
        name: 'hand',
        buybuybuy: function () {
            console.log('this::', this.name)
        }
    }
   
};
// this:: hand,只看buybuybuy最后是被谁调用的
teacher.hand.buybuybuy();
var teacher = {
    name: 'teacher',
    buybuybuy: function () {
        console.log('this::', this.name)
    }

};
var wife = {
    name: 'wife',
};

//--------------------------------------------------
wife.buybuybuy = teacher.buybuybuy;
wife.buybuybuy();   // 这个this是wife

//--------------------------------------------------
var buybuybuy = wife.buybuybuy;  //此处点出来没执行,只是点出来一个function
buybuybuy();     // 此时是自然执行,非严格模式,是全局

//--------------------------------------------------
window.addEventListener('scroll', wife.buybuybuy)  // 全局

function addEventListener (name, func) {
    func();   // 执行时是全局
}

//--------------------------------------------------
var a = (1, 2);  // 逗号,返回第二个值

var buybuybuy = (1, teacher.buybuybuy);
buybuybuy();   // this是全局

(1, teacher.buybuybuy)();   // ()执行,this是全局

2.3 new一个实例时(this是new执行时new出来的对象)

JS中模拟类用的是function,new一个类的构造函数

function Person() {
    console.log('this::', this)
}
var teacher = new Person();

// this就是teacher(new出来的对象)
// console出来的是teacher的构造函数 Person {}
function Person() {
    this.buybugbuy = function () {    // 隐式绑定
        console.log('this::', this);
    }
}
var teacher = new Person();
wife.buybugbuy = teacher.buybugbuy;
wife.buybugbuy();   // this是wife  wife调用的  

2.4 call / apply / bind 强行改变this

  • call / apply / bind对比
function buybuybuy(first, second) {
    console.log('this::', this, first, second);
}
var wife = {
    name: 'wife',
}

buybuybuy();   // 全局 undefined undefined
buybuybuy.call(wife, 1, 2);  // this:: { name: 'wife' } 1 2
buybuybuy.apply(wife, [3, 4]); // this:: { name: 'wife' } 3 4

// call apply都是立刻执行, bind并非立即执行
// bind返回了一个新函数,是绑定过对象的函数,不改原函数
var wifeBuybuybuy = buybuybuy.bind(wife);
buybuybuy(); // 全局
wifeBuybuybuy();   // { name: 'wife' } undefined undefined
teacher.wifeBuybuybuy();  // wifeBuybuybuy已经被bind绑定过了,不执行teacher规则
  • 手写一个bind
var newBind = function (context) {
    const func = this;  // 调用newBind的函数是this func
    return function () {
        func.apply(context, arguments);
    }
}
Function.prototype.newBind = newBind;
  • React中应用bind实例,为什么需要bind
class SubApp extends React.Component {
    render() {
    	var del = this.props.delete;  // 拿到父组件传来的delete
        del();  // 不是被点出来,执行那刻,未被绑定过传递,不知道this是谁
        return <div onClick={del}></div>
    }
}
class App extends React.Component {
    delete() {
    	console.log(this)  // this是app的实例
    	this.xxx
    }
    render() {
        // 父组件传递时候绑定过this,子组件接收后不会丢失this
        // .bind(this)  App实例 给子组件传递绑定的函数 有性能问题
    	return <SubApp onClick = {this.delete.bind(this)} />  
       
    }
}

2.5 箭头函数

  • 箭头函数this指向箭头函数定义时, 离箭头函数最近非箭头 函数执行上下文的this
  • 例1
const outer = () => {
    console.log('this::', this)
}
var wife = {
    name: 'wife',
}
wife.outer = outer;
wife.outer();   // this并不是wife,而是全局
  • 例2
function buybuybuyOuter() {
    console.log('this-outer::', this);
    // 定义时
    // this就是离我最近的非箭头函数的上下文的this
    const buybuybuy = () => {
        console.log('this::', this);
    }
    buybuybuy();    // { name: 'wife', buybuybuyOuter: [Function: buybuybuyOuter] }
}
var wife = {
    name: 'wife'
}
wife.buybuybuyOuter = buybuybuyOuter;
wife.buybuybuyOuter();   // { name: 'wife', buybuybuyOuter: [Function: buybuybuyOuter] }
  • 例3
function buybuybuyOuter() {
    console.log('this-outer::', this);  // wife
    const buybuybuy = () => {
        console.log('this::', this);  //wife
    }
    function innerCall(){
        console.log('innerCall::', this);
        buybuybuy();
    }
    innerCall();   // 全局
}
var wife = {
    name: 'wife'
}
wife.buybuybuyOuter = buybuybuyOuter;
wife.buybuybuyOuter();   // 顺序 this-outer::wife   innerCall::winows   this::wife

this 不听 all bind apply 不听 三板斧