溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Javascript如何使用.call()和.apply()編寫更好的代碼

發布時間:2022-02-23 11:35:15 來源:億速云 閱讀:167 作者:小新 欄目:開發技術

小編給大家分享一下Javascript如何使用.call()和.apply()編寫更好的代碼,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

Javascript函數對象的原型公開了兩個有價值的方法,分別是call()和apply()。

首先,讓我們了解每種方法的作用。

.call()

作用

call()函數用于通過為其提供的this的上下文來調用函數。它允許我們通過在特定函數內顯式提供用于this事件的對象來調用函數。

為了更好地了解為什么存在這種方法,請考慮以下示例:

function sayHello() {
    console.log(`Hello, ${this.name}`);
}

sayHello(); // Hello, undefined

如你所見,this函數內部指的是全局作用域。在上面的代碼中,sayHello函數試圖在全局范圍內查找名為name變量。由于不存在這樣的變量,它打印出undefined. 如果我們定義了一個在全局范圍內調用的name變量,該函數將按預期工作,如下所示:

const name = 'archeun';
function sayHello() {
    console.log(`Hello, ${this.name}`);
}

sayHello(); // Hello, archeun
如果我們嚴格在上面的代碼中使用了模式,它實際上會拋出一個運行時錯誤,因為this將是未定義的。

這里的缺點是sayHello函數假定this變量的范圍,我們無法控制它。根據我們執行它的詞法范圍,該函數的行為會有所不同。這時候call()方法派上用場了。如你所知,它允許我們顯式注入我們需要用于this函數內部變量的對象:

考慮下面的例子:

const name = 'archeun';
function sayHello() {
    console.log(`Hello, ${this.name}`);
}

sayHello(); // Hello, archeun

const visitor = {
    name: 'My lord!'
}

/**
 * The first parameter of the call method is,
 * the object to be used for the `this` context inside the function.
 * So when the `sayHello` function encounters `this.name`, it now knows
 * to refer to the `name` key of the `visitor` object we passed
 * to the `call` method.
 */
sayHello.call(visitor); // Hello, My lord!

/**
 * Here we do not provide the `this` context.
 * This is identical to calling sayHello().
 * The function will assume the global scope for `this`.
 */
sayHello.call(); // Hello, archeun

除了this作為方法的第一個參數傳遞的上下文之外,call()還接受被調用函數的參數。在第一個參數之后,我們傳遞給call()方法的所有其他參數都將作為參數傳遞給被調用函數。

function sayHello(greetingPrefix) {
    console.log(`${greetingPrefix}, ${this.name}`);
}

const visitor = {
    name: 'My lord!'
}

/**
 * Here `Hello` will be passed as the argument to the
 * `greetingPrefix` parameter of the `sayHello` function
 */
sayHello.call(visitor, 'Hello'); // Hello, My lord!

/**
 * Here `Howdy` will be passed as the argument to the
 * `greetingPrefix` parameter of the `sayHello` function
 */
sayHello.call(visitor, 'Howdy'); // Howdy, My lord!

使用方法

1. 可重用的上下文無關函數

我們可以編寫一個函數并在不同的this上下文中調用它:

function sayHello(greetingPrefix) {
    console.log(`${greetingPrefix}, ${this.name}`);
}

const member = {
    name: 'Well-known member'
}

const guest = {
    name: 'Random guest'
}

/**
 * `sayHello` function will refer to the `member` object
 * whenever it encouneters `this`
 */
sayHello.call(member, 'Hello'); // Hello, Well-known member

/**
 * `sayHello` function will refer to the `guest` object
 * whenever it encouneters `this`
 */
sayHello.call(guest, 'Howdy'); // Howdy, Random guest

如你所見,如果使用得當,這會提高代碼的可重用性和可維護性。

2. 構造函數鏈

我們可以使用call()方法來鏈接通過函數創建的對象的構造函數。使用該函數創建對象時,函數可以采用另一個函數作為其構造函數。如下例所示,DogFish都調用Animal函數來初始化它們的公共屬性,即namenoOfLegs

function Animal(name, noOfLegs) {
    this.name = name;
    this.noOfLegs = noOfLegs;
}

function Dog(name, noOfLegs) {
    // Reuse Animal function as the Dog constructor
    Animal.call(this, name, noOfLegs);
    this.category = 'mammals';
}

function Fish(name, noOfLegs) {
    // Reuse Animal function as the Fish constructor
    Animal.call(this, name, noOfLegs);
    this.category = 'fish';
}

const tiny = new Dog('Tiny', 4);
const marcus = new Fish('Marcus', 0);

console.log(tiny); // {name: "Tiny", noOfLegs: 4, category: "mammals"}
console.log(marcus); // {name: "Marcus", noOfLegs: 0, category: "fish"}

這也是代碼重用的一種變體。這種模式還使我們能夠用其他語言編寫接近 OOP 原則的代碼。

3. 使用對象調用匿名函數

匿名函數繼承調用它們的詞法作用域。我們可以使用call()方法將this作用域顯式注入匿名函數??紤]下面的例子:

const animals = [
    { type: 'Dog', name: 'Tiny', sound: 'Bow wow' },
    { type: 'Duck', name: 'Marcus', sound: 'Quack' }
];

for (let i = 0; i < animals.length; i++) {
    /**
     * This anonymous function now has access to each animal object
     * through `this`.
     */
    (function (i) {
        this.makeSound = function () {
            console.log(`${this.name} says ${this.sound}!`);
        }
        this.makeSound();
    }).call(animals[i], i);
}

// Tiny says Bow wow!
// Marcus says Quack!

在這里,我們不必實現一個專門的函數來將makeSound方法附加到每個動物對象上。這使我們無法編寫和命名一次性使用的實用程序函數。

這些是我們可以有效地使用call()方法使我們的代碼干凈、可重用和可維護的幾種方法。

.apply()

作用

apply()在功能方面幾乎與call()方法相同。唯一的區別是它接受一個類似數組的對象作為它的第二個參數。

/**
 * After `this` context argument
 * `call` accepts a list of individual arguments.
 * Therefore, if `args` is an array, we can use the
 * `ES6` spread operator to pass individual elements
 * as the list of arguments
 */
func.call(context, ...args);

/**
 * After `this` context argument
 * `apply` accepts a single array-like object
 * as its second argument.
 */
func.apply(context, args);

除了apply()如何處理被調用方參數外,該功能與call()方法相同。但是,由于這種差異,我們可以將其用于不同于call()的用例。

使用方法

1. 連接(追加)數組

Array.prototype.push函數可用于將元素推送到數組的末尾。例如:

const numbers = [1, 2, 3, 4];
numbers.push('a', 'b', 'c'); // push elements on by one

console.log(numbers); // [1, 2, 3, 4, "a", "b", "c"]

如果你想將一個數組的所有元素推送到另一個數組,該怎么辦?像下面這樣:

const numbers = [1, 2, 3, 4];
const letters = ['a', 'b', 'c'];

numbers.push(letters);

console.log(numbers); // [1, 2, 3, 4, ["a", "b", "c"]]

這并不是我們想要的。它將整個字母數組作為單個元素附加到數字數組。我們本可以使用concat()方法,但它將創建數組的副本并返回它。我們也不需要。我們還可以在字母數組上循環并單獨推送每個元素。但還有一種更優雅的方式:

const numbers = [1, 2, 3, 4];
const letters = ['a', 'b', 'c'];

numbers.push.apply(numbers, letters);

console.log(numbers); // [1, 2, 3, 4, "a", "b", "c"]

如果我們有特權使用ES6擴展運算符,我們可以通過這樣做來實現這一點,

const numbers = [1, 2, 3, 4];
const letters = ['a', 'b', 'c'];

numbers.push(...letters);

console.log(numbers); // [1, 2, 3, 4, "a", "b", "c"]
2.apply()與接受參數列表的內置函數一起使用

對于任何接受參數列表的函數,例如Math.max我們可以有效地使用 apply??紤]以下。

如果你想找出一組數字的最小值和最大值,下面是老派的做法:

let min = +Infinity;
let max = -Infinity;
const numbers = [4, 5, 1, 2, 8, 3, 4, 6, 3];

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > max) {
    max = numbers[i];
  }
  if (numbers[i] < min) {
    min = numbers[i];
  }
}

console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 8

我們可以apply()以更優雅的方式實現相同的效果,如下所示:

const numbers = [4, 5, 1, 2, 8, 3, 4, 6, 3];

min = Math.min.apply(null, numbers);
max = Math.max.apply(null, numbers);

console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 8

與前一種情況相同,如果我們可以使用ES6擴展運算符,我們可以通過執行以下操作來實現相同的效果:

const numbers = [4, 5, 1, 2, 8, 3, 4, 6, 3];

min = Math.min(...numbers);
max = Math.max(...numbers);

console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 8

看完了這篇文章,相信你對“Javascript如何使用.call()和.apply()編寫更好的代碼”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女