this與bind(this) (es5新增)


this與bind(this)

this

this指向的是當前函數的作用域(對象實例),有如下的例子

const app = {
    name: 'xiaoming',
    log() {
      console.log(this.name);
    },
    child() {
      return {
        name: 'b',
        log() {
          console.log(this.name);
        },
      };
    },
  };
  app.log(); // xiaoming
  app.child().log(); // b

this詳細

- 全局環境

無論是否在嚴格模式(‘use strict’)下,在全局執行環境中(在任何函數體外部)this 都指向全局對象。

console.log(this === window); // true

this.name = 'react';
console.log(name); // react
console.log(window.name); // react

- 函數內

在函數內部,this的值取決於函數被調用的方式。

1. 普通函數

非嚴格模式下,this默認指向全局對象。

function f() {
  return this;
}

// brower
f() === window;
// node
f() === global;

嚴格模式下,this默認指向調用函數的對象實例。

function f() {
  'use strict'
  return this;
}
f() === undefined;
因為這里的f()是直接調用的,而不是作為對象的屬性或方法調用的,如window.f(),所以這里的this為undefined。

如果要想把 this 的值從一個環境傳到另一個,就要用 call 或者apply 方法

var obj = {a: 'Custom'};

// 這個屬性是在global對象定義的。
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // this的值取決於函數的調用方式
}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'

在JavaScript定義的函數都繼承自Function,我們可以通過Function.prototype屬性里的call或apply方法將 this 值綁定到調用中的特定對象。

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一個參數是作為‘this’使用的對象
// 后續參數作為參數傳遞給函數調用
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
// 第一個參數也是作為‘this’使用的對象
// 第二個參數是一個數組,數組里的元素用作函數調用中的參數
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

使用 call 和 apply 函數的時候要注意,如果傳遞給 this 的值不是一個對象,JavaScript 會嘗試使用內部 ToObject 操作將其轉換為對象。因此,如果傳遞的值是一個原始值比如 7 或 ‘foo’,那么就會使用相關構造函數將它轉換為對象,所以原始值 7 會被轉換為對象,像 new Number(7) 這樣,而字符串 ‘foo’ 轉化成 new String(‘foo’) 這樣,例如:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隱式轉換為對象
bar.call(7); // [object Number]

2. 箭頭函數

箭頭函數沒有自己的this指針。通過 call() 或 apply() 方法調用一個函數時,只能傳遞參數(不能綁定this)。在封閉的詞法環境中,箭頭函數的this和普通函數的this一致;在全局代碼里,箭頭函數的this被設置為全局對象。

var obj = {
  bar: function() {
    var x = (()=> this);
    return x;
  }
}
// 以obj為對象來調用bar(),所以this綁定的是obj
var fn = obj.bar();
console.log(fn() === obj); // true

// 這里並沒有調用bar(),只是引用bar賦給fn2
var fn2 = obj.bar;
// 使用全局變量來調用bar(),所以這里的this綁定全局
console.log(fn2()() == window);

3. 對象中的函數

當函數在對象中被調用時,this指向的是調用該函數的對象。

const app = {
  name: 'xiaohong',
  f: function() {
    console.log(this.name);
  }
}

f() 函數里的this指向的是app對象。

this 的綁定只受最靠近的成員引用的影響。例如:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42

事實證明,這與他是對象 o 的成員沒有多大關系,最靠近的引用才是最重要的。

原型鏈中的this

如果該方法存在於一個對象的原型鏈上,那么this指向的是調用這個方法的對象,就像該方法在對象上一樣。

var o = {
  f: function() { 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

在這個例子中,對象p沒有屬於它自己的f屬性,它的f屬性繼承自它的原型。雖然在對 f 的查找過程中,最終是在 o 中找到 f 屬性的,這並沒有關系;查找過程首先從 p.f 的引用開始,所以函數中的 this 指向p。也就是說,因為f是作為p的方法調用的,所以它的this指向了p。

getter 與 setter 中的 this
用作 getter 或 setter 的函數都會把 this 綁定到設置或獲取屬性的對象。

bind(this)
ES5 引入了 Function.prototype.bind。調用f.bind(someObject)會創建一個與f具有相同函數體和作用域的函數,但是在這個新函數中,this將永久地被綁定到了bind的第一個參數,無論這個函數是如何被調用的。bind綁定的參數只生效一次

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty

傳入bind的第二個參數以及后面的,依照先后順序構成綁定函數的參數。

var foo = {
    x: 3
} 
var bar = function(){
    console.log(this.x);
} 
bar(); // undefined

var boundFunc = bar.bind(foo);

boundFunc(); // 3

有時候,我們須要保持this的上下文,也就是在一個運行環境中,想要訪問到的this值。在什么時候須要這么做呢?

比方說將一個對象的方法賦值給了一個全局變量,然后在全局變量中調用這種方法,那么this值就不再是原來的對象而是window對象了。但是我們還需要依照對象的方法來調用。

又比方說一個方法中包括了閉包,閉包是無法訪問到其外部函數的this對象的,由於this對象是在調用方法的時候自己主動生成,內部函數在搜索這兩個變量的時候僅僅會搜索到其自身的活動對象。而不會沿着作用域鏈往外搜索,所以閉包訪問不到外部函數的this值。

在react中,常看到

export default class App extends Component {
  constructor(props) {
    super(props);
    this.foo = this.foo.bind(this);
  }
  
  foo() {
    // todo something
  }
  
  render() {
    return (
      <View>
        <Button onPress={this.foo()}/>
      </View>
    )
  }
}

如果你傳遞一個函數名給一個變量,然后通過在變量后加括號’()'來調用這個方法,此時方法內部的this的指向就會丟失。這就會出現外部的foo方法內部的this會丟失指向。

為了解決這個問題,我們需要在實例化對象的時候,需要在構造函數中綁定this,使得無論事件處理函數如何傳遞,它的this的指向都是固定的,固定指向我們所實例化的對象。

原文鏈接:https://blog.csdn.net/u013003052/article/details/87894194


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM