Borrowing methods in JavaScript

In JavaScript, sometimes you can reuse the functions or methods of other objects, not necessarily defined on the object itself or prototype. Through the call(), apply() and bind() methods, we can easily borrow methods from other objects without having to inherit these objects. This is a common method used by professional JavaScript developers.

premise

This article assumes that you have mastered the relevant knowledge of using call(), apply() and bind() and the difference between them.

Prototype method

In JavaScript, except for the unchangeable primitive data types, such as string, number, and boolean, almost all data is an object. Array is an object suitable for traversing and transforming an ordinal sequence. Its prototype has useful methods such as slice, join, push and pop.

A common example is that when the object and the array are both list-type data structures, the object can "borrow" methods from the array. The most commonly borrowed method is Array.prototype.slice.


function myFunc() {

    // error, arguments is an array like object, not a real array

    arguments.sort();

    // "borrow" the Array method slice from its prototype, which takes an array like object (key:value)

    // and returns a real array

    var args = Array.prototype.slice.call(arguments);

    // args is now a real Array, so can use the sort() method from Array

    args.sort();

}

myFunc('bananas', 'cherries', 'apples');

Borrowing methods are feasible because the call and apply methods allow functions to be called in different contexts. This is also a good way to reuse existing functions without inheriting other objects. In fact, arrays define many common methods in the prototype, such as join and filter:


// takes a string "abc" and produces "a|b|c

Array.prototype.join.call('abc', '|');

// takes a string and removes all non vowels

Array.prototype.filter.call('abcdefghijk', function(val) {

    return ['a', 'e', 'i', 'o', 'u'].indexOf(val) !== -1;

}).join('');

It can be seen that not only objects can borrow array methods, but also strings. But because generic methods are defined on the prototype, you must use String.prototype or Array.prototype every time you want to borrow a method. Writing like this is very verbose and quickly becomes annoying. A more effective way is to use literals to achieve the same purpose.

Use literal borrowing method

A literal is a grammatical structure that follows the rules of JavaScript, MDN explains it like this:

In JavaScript, you can use literals to represent values. They are fixed values, not variables, or given literally in the script.

Literals can be abbreviated as prototype methods:


[].slice.call(arguments);

[].join.call('abc', '|');

''.toUpperCase.call(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');

This doesn't look so verbose, but you must operate directly on [] and "" to borrow methods, which is still a bit ugly. You can use variables to save references to literals and methods, which makes it easier to write:


var slice = [].slice;

slice.call(arguments);

var join = [].join;

join.call('abc', '|');

var toUpperCase = ''.toUpperCase;

toUpperCase.call(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');

With the reference to the borrowed method, we can easily call it with call(), so that the code can also be reused. With the principle of reducing redundancy, let’s see if we can borrow methods without having to write call() or apply() every time we call:


var slice = Function.prototype.call.bind(Array.prototype.slice);

slice(arguments);

var join = Function.prototype.call.bind(Array.prototype.join);

join('abc', '|');

var toUpperCase = Function.prototype.call.bind(String.prototype.toUpperCase);

toUpperCase(['lowercase', 'words', 'in', 'a', 'sentence']).split(',');

As you can see, you can now use Function.prototype.call.bind to statically bind methods "borrowed" from different prototypes. But how does var slice = Function.prototype.call.bind(Array.prototype.slice) actually work?

理解 Function.prototype.call.bind

Function.prototype.call.bind may seem complicated at first glance, but understanding how it works can be very helpful.

  • Function.prototype.call is a kind of reference, you can "call" the function and set its "this" value to use in the function.

  • Note that "bind" returns a new function with its "this" value stored. Therefore, the "this" of the new function returned by .bind(Array.prototype.slice) is always the Array.prototype.slice function.

In summary, the new function will call the "call" function, and its "this" is the "slice" function. Calling slice() will point to the previously defined method.

Methods of customizing objects

Inheritance is great, but developers usually use it when they want to reuse some common functionality between objects or modules. There is no need to use inheritance only for code reuse, because simple borrowing methods will be complicated in most cases.

Before, we only discussed borrowing native methods, but any method is fine. For example, the following code can calculate the player's score for a point game:


var scoreCalculator = {

    getSum: function(results) {

        var score = 0;

        for (var i = 0, len = results.length; i < len; i++) {

            score = score + results[i];

        }

        return score;

    },

    getScore: function() {

        return scoreCalculator.getSum(this.results) / this.handicap;

    }

};

var player1 = {

    results: [69, 50, 76],

    handicap: 8

};

var player2 = {

    results: [23, 4, 58],

    handicap: 5

};

var score = Function.prototype.call.bind(scoreCalculator.getScore);

// Score: 24.375

console.log('Score: ' + score(player1));

// Score: 17

console.log('Score: ' + score(player2));

Although the above example is very blunt, it can be seen that just like native methods, user-defined methods can be easily borrowed.

to sum up

Call, bind and apply can change the way a function is called, and are often used when borrowing a function. Most developers are familiar with borrowing native methods, but seldom borrowing custom methods.

In recent years, functional programming in JavaScript has developed well. How to use the Function.prototype.call.bind method to make it easier? It is estimated that such topics will become more and more common.

Guess you like

Origin blog.51cto.com/15080022/2588837