Anti corrilization in JS

Posted by starmikky on Mon, 13 Dec 2021 16:59:59 +0100

As a functional programming language, JS brings many interesting language features, such as curry and anti curry.

You can refer to another introduction JS Coriolis Read your articles together~

1. Introduction

Coriolism is to fix some parameters and return a function that accepts the remaining parameters, also known as partial calculation function. The purpose is to narrow the scope of application and create a more targeted function. The core idea is to divide the function passed in by multiple parameters into single parameter (or part) functions, and then call the next single parameter (or part) function to process the remaining parameters in turn.

The anti Coriolis, literally speaking, has the opposite meaning and usage compared with the function Coriolis. It expands the scope of application and creates a function with a wider scope of application. The method that is originally applicable only to specific objects is extended to more objects.

2. Realization

Let's take a look at the general implementation of anti coritization~

Function.prototype.unCurrying = function() {
  const self = this
  return function(...rest) {
    return Function.prototype.call.apply(self, rest)
  }
}

Explain:

  1. Add the uncurrying method to the Function prototype, and save the uncurrying method to self when executing
  2. Borrow apply, assign the function to be borrowed to call as this environment, and execute the passed formal parameters as parameters

There is another implementation:

Function.prototype.unCurrying = function() {
  return this.call.bind(this)
}

If you think putting a function in function The prototype is not very good. You can also do this:

function unCurrying(fn) {
  return function(tar, ...argu) {
    return fn.apply(tar, argu)
  }
}

3. Use

3.1 simple use

Use unCurrying general to realize simple and practical. Try it:

Function.prototype.unCurrying = function() {
  const self = this                        // self here is array prototype. Push method
  return function(...rest) {              // rest is the two-tier parameter passed in [[1,2,3], 4]
    return Function.prototype.call.apply(self, rest)
  }
}
const push = Array.prototype.push.unCurrying()

~function(...rest) {       // rest:[1,2,3]
  push(rest, 4)
  console.log(rest)    // [1, 2, 3, 4]
}(1, 2, 3)

3.2 borrowing other methods

Anti currying actually reflects an idea, that is, expand the scope of application of the method, still call the general unCurrying method just now, and borrow the push method:

const push = Array.prototype.push.unCurrying()

const obj = { a: 'Hee hee' }
push(obj, 'ha-ha', 'ha-ha', 'hey')
console.log(obj)                    // {'0': 'ha ha', '1': 'ha ha', '2': 'ha ha', a: 'hee hee', length: 3}

Equivalent to obj push(...), Obj not only has a number index attribute similar to an array, but also has a length attribute similar to an array, allowing the engine to automatically manage array members and length attributes; (there is the source code of the push method implemented by V8 engine)
The push method of such an array is borrowed and can be applied to any other object.

As long as it is a method, unCurrying can be borrowed, and the call method can also:

var call = Function.prototype.call.unCurrying();
function $(id) {
    return this.getElementById(id);
}
call($, document, 'demo')            // #demo element

Equivalent to document$ ('demo '), successfully borrowed the call method. Of course, you can change the document to any object you want to bind to $as this, such as {getelementbyid: T = > console.log (T +' er ')} / / demo er

3.3 borrowing oneself

unCurrying itself is also a method. You can also borrow yourself... --

const unCurrying = Function.prototype.unCurrying.unCurrying()
const map = unCurrying(Array.prototype.map)
map({ 0: 4, 1: 'a', 2: null, length: 3 }, n => n + n)                    // [8, "aa", 0]

It's amazing~

4. Summary

In short, function coriolism is to reduce the order of higher-order functions, narrow the scope of application and create a more targeted function. Lift chestnuts:

function(arg1,arg2)        // => function(arg1)(arg2)
function(arg1,arg2,arg3)        // => function(arg1)(arg2)(arg3)
function(arg1,arg2,arg3,arg4)        // => function(arg1)(arg2)(arg3)(arg4)
function(arg1,arg2,...,argn)        // => function(arg1)(arg2)...(argn)

The reverse is to increase the scope of application and make the method use scenario larger. Using unCurrying, you can borrow the native method and let any object have the method of the native object. For example, chestnuts:

obj.func(arg1, arg2)        // => func(obj, arg1, arg2)

It can also be understood as follows:
Coriolism is to pass parameters before operation, and multiple parameters can be passed;
Anti corrilization is to delay the transfer of parameters. During operation, the original fixed parameters or this context are regarded as parameters and delayed to the future.

Attached:

Array in V8 engine prototype. Source code implementation of push method:

function ArrayPush() {
    var n = TO_UINT32(this.length);
    var m = %_ArgumentsLength();
    for (var i = 0; i < m; i++) {
        this[i + n] = %_Arguments(i);        // Attribute copy
        this.length = n + m;                    // Corrected length
        return this.length;
    }
}

Most of the online posts are different in depth and even contradictory. The next articles are a summary of the learning process. If you find an error, you are welcome to leave a message and point it out~

Topics: Javascript Front-end