JavaScript中的方法是什麼

做者:Shadeed
譯者:前端小智
來源:dmitripavlutin

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。javascript

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。前端

1.什麼是方法

定義並調用一個常規函數:java

function greet(who) {
  return `Hello, ${who}!`;
}

greet('World'); // => 'Hello, World!'

function關鍵字後跟其名稱,參數和主體:function greet(who){...}進行常規的函數定義。git

greet('World')是常規的函數調用。函數greet('World')接受參數中的數據。github

若是who是一個對象的屬性呢?要方便訪問對象的屬性,咱們能夠將函數附加到該對象,換句話說,就是建立一個方法。面試

咱們將greet()做爲對象world的一種方法:windows

const world = {
  who: 'World',

 greet() { return `Hello, ${this.who}!`; }}

world.greet(); // => 'Hello, World!'

greet() { ... }如今是屬於world對象的方法, world.greet()是方法調用。瀏覽器

greet()方法內部,this指向該方法所屬的對象—world,這就是爲啥能夠this.who訪問 word屬性的緣由。微信

注意,this也稱爲上下文。app

上下文是可選的

在上一個示例中,咱們使用this來訪問該方法所屬的對象,可是 JS 沒有強制讓方法使用 this

所以,能夠將對象用做方法的命名空間:

const namespace = {
  greet(who) {
    return `Hello, ${who}!`;
  },

  farewell(who) {
    return `Good bye, ${who}!`;
  }
}

namespace.greet('World');    // => 'Hello, World!'
namespace.farewell('World'); // => 'Good bye, World!'

namespace是一個包含2個方法的對象:namespace.greet()namespace.farewell()

2. 對象字面量方法

如前所述,咱們能夠直接在對象字面量中定義方法

const world = {
  who: 'World',

 greet() { return `Hello, ${this.who}!`; }};

world.greet(); // => 'Hello, World!'

greet() { .... }是在對象定義的方法,這種定義類型稱爲速記方法定義(從ES2015開始可用)。方法定義的語法也更長:

const world = {
  who: 'World',
  greet: function() { 
    return `Hello, ${this.who}!`; 
  }
}

world.greet(); // => 'Hello, World!'

greet: function() { ... }是一個方法定義,注意附加的冒號和function關鍵字。

動態添加方法

方法只是一個函數,它做爲屬性存儲在對象上。 所以,咱們能夠向對象動態添加方法:

const world = {
  who: 'World',

  greet() {
    return `Hello, ${this.who}!`;
  }
};

// A a new property holding a function
world.farewell = function () {
  return `Good bye, ${this.who}!`;
}

world.farewell(); // => 'Good bye, World!'

3.類方法

在 JavaScript 中,類別語法定義了一個類別,該類別將用做其實例的模板。

類也能夠有方法:

class Greeter {
  constructor(who) {
    this.who = who;
  }

 greet() { console.log(this === myGreeter); // logs true return `Hello, ${this.who}!`; }}

const myGreeter = new Greeter('World');
myGreeter.greet(); // => 'Hello, World!'

greet() { ... }是在類內部定義的方法。

每次咱們使用new操做符(例如myGreeter = new Greeter('World'))建立一個類的實例時,均可以在建立的實例上調用方法。

myGreeter.greet()是如何在實例上調用方法greet()的方法。 重要的是方法內部的this等於實例自己:this等於greet() { ... }方法內部的 myGreeter

4.如何調用方法

4.1方法調用

JavaScript 特別有趣的是,在對象或類上定義方法只能算完成工做的一半。爲了維護方法的上下文,咱們必須確保將方法做爲方法調用。

咱們來看看爲何它很重要。

回憶一下有greet()方法的world對象。咱們測試一下greet()做爲一個方法和一個常規函數調用時,this值是什麼:

const world = {
  who: 'World',

  greet() {
 console.log(this === world);    return `Hello, ${this.who}!`;
  }
};

// 方法調用
world.greet(); // logs true
const greetFunc = world.greet;
// 常規函數調用
greetFunc(); // => logs false

world.greet()是一個方法調用。對象world,後面是一個點.,最後是使方法調用的方法自己。

greetFuncworld.greet是同一個函數。但看成爲常規函數greetFunc()調用時,這個在greet()中的並不等於world對象,而是全局對象(在瀏覽器中是window)

咱們將諸如greetFunc = world.greet之類的表達式命名爲將方法與其對象分離的方法。 調用分離的方法greetFunc()時,this等於全局對象。

將方法與其對象分離能夠採用不一樣的形式:

// 方法分離, this 丟失了!
const myMethodFunc = myObject.myMethod;

// 方法分離, this 丟失了!
setTimeout(myObject.myMethod, 1000);

// 方法分離, this 丟失了!
myButton.addEventListener('click', myObject.myMethod)

// 方法分離, this 丟失了!
<button onClick={myObject.myMethod}>My React Button</button>

爲了不丟失方法的上下文,請確保使用方法調用world.greet()或手動將方法綁定到對象greetFunc = world.greet.bind(this)

4.2間接函數調用

如上一節所述,常規函數調用已將this解析爲全局對象。 常規函數是否能夠經過方法自定義 this值?

歡迎使用如下間接函數調用:

myFunc.call(thisArg, arg1, arg2, ..., argN);
myFunc.apply(thisArg, [arg1, arg2, ..., argN]);

函數對象上可用的方法。

myFunc.call(thisArg)myFunc.apply(thisArg) 的第一個參數是間接調用的上下文(this值)。 換句話說,咱們能夠手動指定函數內部 this 的值。

例如,讓咱們將greet()定義爲一個常規函數,以及一個具有who屬性的對象alien:

function greet() {
  return `Hello, ${this.who}!`;
}

const aliens = {
  who: 'Aliens'
};

greet.call(aliens); // => 'Hello, Aliens!'
greet.apply(aliens); // => 'Hello, Aliens!'

greet.call(aliens)greet.apply(aliens)都是間接的方法調用。這個在greet()函數中的值等於aliens對象。

4.3 綁定函數調用

最後,還有一種在對象上使函數做爲方法調用的第三種方法。 咱們能夠將函數綁定爲具備特定上下文。

可使用特殊方法建立綁定函數

const myBoundFunc = myFunc.bind(thisArg, arg1, arg2, ..., argN);

myFunc.bind(thisArg)的第一個參數是函數要綁定到的上下文。

例如,讓咱們重用greet()並將其綁定到aliens上下文

function greet() {
  return `Hello, ${this.who}!`;
}

const aliens = {
  who: 'Aliens'
};

const greetAliens = greet.bind(aliens);

greetAliens(); // => 'Hello, Aliens!'

調用 greet.bind(aliens) 會建立一個新函數,該函數將 this 綁定到aliens對象。

一樣,使用綁定函數能夠模擬方法調用。當調用綁定函數greetAliens()時,this等於該函數中的 aliens

5. 箭頭函數做爲方法

不推薦使用箭頭函數做爲方法,緣由以下。

咱們將greet()方法定義爲一個箭頭函數:

const world = {
  who: 'World',

  greet: () => {
    return `Hello, ${this.who}!`;
  }
};

world.greet(); // => 'Hello, undefined!'

不幸的是,world.greet()返回'Hello, undefined!而不是咱們期待的'Hello, World!'

問題是箭頭函數內部的this等於外部做用域的this。 可是,此時,咱們想要的thisworld對象。

上述箭頭功能內部 this 等於全局對象:window'Hello, ${this.who}!' 結果是 Hello, ${windows.who}!,最後是 'Hello, undefined!'

我喜歡箭頭功能, 可是它們不能用做方法。

6. 總結

該方法是一個屬於對象的函數。方法的上下文(this)等於該方法所屬的對象。

還能夠在類上定義方法。這個類的方法內部等於實例。 JS 特有的一點是,僅僅定義一個方法是不夠的。咱們還須要確保使用方法調用。一般,方法調用具備如下語法

// Method invocation
myObject.myMethod('Arg 1', 'Arg 2');

有趣的是,在 JS 中,咱們能夠定義一個常規函數,但不屬於一個對象,而後做爲一個任意對象的方法調用該函數。可使用間接函數調用或將函數綁定到特定上下文來實現這一點

// Indirect function invocation
myRegularFunc.call(myObject, 'Arg 1', 'Arg 2');
myRegularFunc.apply(myObject, 'Arg 1', 'Arg 2');

// Bound function
const myBoundFunc = myRegularFunc.bind(myObject);
myBoundFunc('Arg 1', 'Arg 2');

我是小智,我要去刷碗了,咱們下期見~


代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:https://dmitripavlutin.com/ja...

交流

有夢想,有乾貨,微信搜索 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收錄,有一線大廠面試完整考點、資料以及個人系列文章。

相關文章
相關標籤/搜索