淺談react 中的 this 指向

前言 最近在做一個項目的時候 關于class方法中 this 指向以及 外置prototype 的 this 指向 引發(fā)了我的思考!


image.png

ES6原生class

我們假設 A 為 react B 為 我們創(chuàng)建的類 class B extends React.component{}

   class A {
    constructor() {
      this.x = 1;
    }
  }
  class B extends A {
    constructor() {
      super();
      this.x = 2;
      console.log('=====');
      console.log(this);    // B
      console.log(this.x);  // 2
      console.log(super.x); // undefined
      this.getme = this.getme.bind(this)
    }
    getName(){
      console.log('getName');
      console.log(this.x); // B
      let m = this.getme
      m()
    }
    getme(){
      console.log('getme');
      console.log(this.x); // B
    }
  }
  // 類轉(zhuǎn)化為 es5的寫法如下:
  function Es5B() {
    this.x = 2
  }
  Es5B.prototype.getName = function () {
    console.log(this);
    console.log('getName');
    console.log(this.x);
  }

  let b = new B();
  b.getName()

  let esb = new Es5B()
  esb.getName()

打印結(jié)果

image.png

react 高階 api => createElement

https://react.docschina.org/docs/react-without-jsx.html

jsx 語法

class Hello extends React.Component {
  render() {
    return <div>Hello {this.props.toWhat}</div>;
  }
}

ReactDOM.render(
  <Hello toWhat="World" />,
  document.getElementById('root')
);

編譯成下面這段代碼

class Hello extends React.Component {
  render() {
    return React.createElement('div', null, `Hello ${this.props.toWhat}`);
  }
}

ReactDOM.render(
  React.createElement(Hello, {toWhat: 'World'}, null),
  document.getElementById('root')
);

看我們最初的那一段代碼

 // 如果我們將 constructor 中的那個 bind 去掉之后
 // this.getme = this.getme.bind(this)
 // 執(zhí)行到這里  this的指向就變化了
 let m = this.getme
 m() // 此時 this 變化為 undefined

將方法進行賦值之后,丟失了上下文,導致 this 變成 undefined , this之所以沒有變?yōu)閣indow 是因為類聲明和類表達式的主體以 嚴格模式 執(zhí)行,主要包括構(gòu)造函數(shù)、靜態(tài)方法和原型方法。Getter 和 setter 函數(shù)也在嚴格模式下執(zhí)行。

ES6class 注意點

譯文
為什么需要在 React 類組件中為事件處理程序綁定 this

未解之謎 原生 class 中 如果方法改為箭頭函數(shù)這種形式就會報錯 但是在 react 的 class 中 是可以正常渲染的

 class A {
    constructor() {
      this.x = 1;
    }
  }
  class B extends A {
    constructor() {
      super();
      this.x = 2;
    }
    getme=()=>{         // 這里會報錯誤
      console.log('getme');
      console.log(this.x); 
    }
    getName(){
      console.log('getName');
      console.log(this.x); 
      let m = this.getme
      m()
    }
  }
  
  let b = new B();
  b.getName()

內(nèi)置箭頭函數(shù)與外置箭頭函數(shù)是有區(qū)別的

class B extends A {
  constructor() {
    super();
    this.x = 2
  }
  getName(){
    console.log('getName');
    console.log(this.x); // B
    let m = this.getme
    m()
  }
}

  B.prototype.getme =  ()=> {
    console.log('getme');
    console.log(this);
    /*
     箭頭函數(shù)的 this 指向定義時所在對象 定義的環(huán)境在 window
     此時 this 指向 window
     如果是 react 創(chuàng)建的組件  此時 this指向和類之外的 this 是一致的 (但不是 window)
     如果prototype上掛載方法的時候 強烈建議大家用es5的方式就好!
    */
  }


let b = new B();
b.getName()

react 創(chuàng)建組件(需要綁定 this 和綁定 this 的方法)

export default class ExtendsCompTable extends React.Component {
  constructor (props) {
    super(props)
    this.state  = {
      name: 'react測試this指向'
    }
    this.handler = this.handler.bind(this)
  }

  handler () {
    message.info('點擊了 bindthis),通過 bind 綁定 this')
  }
  renderDom () {
    let { name } = this.state
    return <Button>{name}</Button>
  }
  handlerArrow=()=> {
    console.log(this);
    message.info('點擊了箭頭函數(shù)綁定按鈕,通過箭頭函數(shù)綁定 this')
  }
  handleInnerArrow(){
    console.log(this);
    message.info('點擊了箭頭函數(shù)綁定,通過 bind 綁定 this')
  }
  handleBind(){
    console.log(this);
    message.info('點擊了bind')
  }
  render () {
    return (
      <div>
        <h1>234567890</h1>
        <Button type='primary' onClick={this.handler}>bind(this)</Button>
        {/* 這種直接調(diào)用的方式不需要綁定 this  作為對象的方法被調(diào)用 this 指向?qū)ο?/}
        {this.renderDom()}   
        {/* 這種  handlerArrow=()=> {...}的形式  雖然可以用 但是不太建議*/}
        <Button type='primary' onClick={this.handlerArrow}>箭頭函數(shù)綁定</Button>
        <Button type='primary' onClick={() => {
          this.handleInnerArrow()
        }}>點擊觸發(fā)方法</Button>
        <Button type='primary' onClick={this.handleBind.bind(this)}>bind</Button>
        <Table columns={columns} dataSource={data} />
      </div>
    )
  }
}

箭頭函數(shù) ()=>

  • 函數(shù)體內(nèi)的this對象,就是定義時所在的對象,而不是使用時所在的對象,this是繼承自父執(zhí)行上下文??!中的this

    var x=11;
    var obj={
      x:22,
      say:function(){
        console.log(this.x)
      }
    }
    obj.say(); // 22
    
    var x=11;
    var obj={
     x:22,
     say:()=>{
       console.log(this.x);
     }
    }
    obj.say();// 11
    
    var a=11
    function test1(){
      this.a=22;
      let b=function(){
        console.log(this.a);
      };
      b();
    }
    var x=new test1(); // 11
    
    var x=11;
    var obj={
     x:22,
     say:()=>{
       console.log(this.x);
     }
    }
    obj.say(); // 22 
    
  • 箭頭函數(shù)中的 this 對象指向是固定的

  • 不可以當作構(gòu)造函數(shù),也就是說,不可以使用new命令,否則會拋出一個錯誤

bind

無論是 call() 也好, apply() 也好,都是立馬就調(diào)用了對應的函數(shù),而 bind() 不會, bind() 會生成一個新的函數(shù),bind() 函數(shù)的參數(shù)跟 call() 一致,第一個參數(shù)也是綁定 this 的值,后面接受傳遞給函數(shù)的不定參數(shù)。 bind() 生成的新函數(shù)返回后,你想什么時候調(diào)就什么時候調(diào)

var m = {    
    "x" : 1 
}; 
function foo(y) { 
    alert(this.x + y); 
} 
foo.apply(m, [5]); 
foo.call(m, 5); 
var foo1 = foo.bind(m, 5); 
foo1();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • JavaScript中的this指向問題有很多博客在解釋,仍然有很多人問。上周我們的開發(fā)團隊連續(xù)兩個人遇到相關問題...
    一個敲代碼的前端妹子閱讀 710評論 0 5
  • 葡萄藤PPT JS中this的指向 大家好,我是IT修真院鄭州分院第6期的學員王棟,一枚正直、純潔、善良的前端程序...
    17064閱讀 679評論 0 2
  • 40、React 什么是React?React 是一個用于構(gòu)建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,185評論 0 1
  • 1、吳伯凡老師講理智、欲望和恐懼是認知的三元素,或者說是認知三原色。這三樣東西互相作用在不同的情況之下都在不停的你...
    第二夢想閱讀 313評論 0 0
  • 你欲想潛入我的心扉 窺探你在我心中的地位。 但你四顧半天,只發(fā)現(xiàn)這里 是一片空白。 你找到一個和你一模一樣的聲音。...
    伊洋Lyon閱讀 234評論 0 0

友情鏈接更多精彩內(nèi)容