首頁>技術>

1. 什麼是方法

首先讓我們定義並呼叫常規函式:

function greet(who) {  return `Hello, ${who}!`;}greet('World'); // => 'Hello, World!'

常規函式定義的形式為關鍵字 function 後跟名稱、引數和函式體:function greet(who) {...} 。

greet('World') 是常規函式呼叫。函式 greet('World') 從引數接受資料。

如果 who 是物件的屬性怎麼辦?要想輕鬆訪問物件的屬性,可以將函式附加到該物件,也就是建立一個方法。

讓我們把 greet() 作為物件 world 的一個方法:

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

greet() { ... } 現在是屬於 world 物件的一個方法。world.greet()是一種方法呼叫。

在 greet() 方法內部,this 指向該方法所屬的物件 world。這就是為什麼 this.who 表示式能夠訪問屬性 who 的原因。

this 也叫上下文(context)

上下文是可選的

在上個例子中,我們用了 this 來訪問該方法所屬的物件,但是 JavaScript 並沒有強制使用 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()。

這些方法沒有用 this,而 namespace 是方法的所有者。

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}!`;  }};// 一個帶有函式的新屬性world.farewell = function () {  return `Good bye, ${this.who}!`;}world.farewell(); // => 'Good bye, World!'

首先,world 物件沒有 farewell 方法,它是被動態新增的。

呼叫動態新增的方法完全沒有問題:world.farewell()。

3. 類方法

在 JavaScript 中,class 語法定義了一個類,該類是它例項的模板。

一個類也可以有方法:

class Greeter {  constructor(who) {    this.who = who;  }  greet() {          console.log(this === myGreeter); // => 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 方法呼叫

物件或類上定義方法只是完成了工作的一半。為了保持方法的上下文,你必須確保將其作為“方法”去呼叫。

回想一下帶有 greet() 方法的 world 物件。讓我們檢查一下當方法和常規函式 greet() 被呼叫時,this 的值是什麼:

const world = {  who: 'World',  greet() {    console.log(this === world);    return `Hello, ${this.who}!`;  }};// 方法呼叫world.greet(); // => trueconst greetFunc = world.greet;// 常規函式呼叫greetFunc(); // => false

world.greet() 是一種方法呼叫。物件 world,後跟一個點 .,最後是方法本身,這就是方法呼叫

greetFunc與world.greet的功能相同。但是當作為常規函式 greetFunc() 呼叫時,greet() 內部的 this 不等於 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 屬性的物件 aliens:

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() 中的 this 值等於 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 等於 world 物件,但是在瀏覽器中 this 是 window。'Hello, ${this.who}!' 的計算結果為 Hello, ${windows.who}!,所以最後的結果是 'Hello, undefined!'。

儘管我很喜歡箭頭函式,但是不能把它們用作方法。

總結

方法是屬於物件的函式。方法的上下文(this值)等於該方法所屬的物件。

你還可以在類上定義方法。類方法中的 this 等於例項。

僅定義一個方法是不夠的,還要能夠呼叫才行。一般方法呼叫實用以下語法:

// 方法呼叫myObject.myMethod('Arg 1', 'Arg 2');

在 JavaScript 中,你可以定義一個不屬於物件的常規函式,然後將該函式作為對任意物件的方法來呼叫。你可以透過間接函式呼叫或將函式繫結到特定上下文來實現:

// 間接函式呼叫myRegularFunc.call(myObject, 'Arg 1', 'Arg 2');myRegularFunc.apply(myObject, 'Arg 1', 'Arg 2');// 繫結函式const myBoundFunc = myRegularFunc.bind(myObject);myBoundFunc('Arg 1', 'Arg 2');

5
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Python零基礎入門—15個最受歡迎的Python開源框架