JavaScript advanced techniques, high-order functions (i) for the road of the front

Source: Internet
Author: User

Directory

    • First, advanced functions
      • 1-1 Safe Type Detection
      • 1-2 Scope-Safe constructors
      • 1-3 Lazy Load function
      • 1-4 function Bindings
      • 1-5 function currying
      • 1-6 Inverse function currying
I. Advanced function 1-1 Safe type detection

Thinking about type detection, the first response in my mind should be the type in the world of Javascript (which is really a very old question)

我们大致分为 2 类: 基本类型 和 引用类型其中 基本类型 包括了: string、number、bool、undefined、null其中 引用类型 包括了: Array、Function、Object

So we'll use type and instanceof to see what these data types determine.
Why is it unsafe to use type and instanceof to detect

const str = 'test'const num = 12const bool = falseconst unde = undefinedconst nulls = nullconst Array = [1,2,3,4]const Object = {name: 'zzz'}const checkType = (type) => {    return typeof(type)}// 使用 type 来判断console.log(checkType(str))         // stringconsole.log(checkType(num))         // numberconsole.log(checkType(bool))        // booleanconsole.log(checkType(unde))        // undefinedconsole.log(checkType(nulls))       // objectconsole.log(checkType(Array))       // objectconsole.log(checkType(Object))      // object// 很显然 null、Array、Object 返回的都是 object 不够安全 ( bug 点 )// 用 instanceof 来判断const checkInstance = (type) => {    return type instanceof String}console.log(checkInstance(str)) // 是 false 这是为什么呢?// 那么我们就需要来介绍下 instanceof 的原理了。
The principle of 1-1-1 instanceof

The function implementation of instanceof is whether the former is the latter instance, the specific code is:
eg

let res = a instanceof A// a 是 A 的实例 // A 是 a 的构造函数// 同时 a 的 __proto__  == A 的 prototype 那么  a instanceof A  == true 否则就等于 false

Several of these key points are as follows:

    • Understanding of the four points of Constrcutor,Proto , prototype, prototype objects.
    • Recommend a good article the triangular relationship between prototype,Protoand constructor

    • Back up, A.__proto__ pointed to the prototype object of a.
    • A.prototype points to the prototype object of the instance object

var Foo = function() {    this.setName = (name) => {        this.name = name    }}var foo = new FooFoo.prototype  指向 => 原型对象(理解为公共对象)// 通过同一个构造函数实例化的多个对象具有相同的原型对象。经常使用原型对象来实现继承Foo.prototype.constructor  指向 => 构造函数本身(Foo)foo.__proto__  指向 => 原型对象(理解为公共对象)foo.constructor 指向 => 构造函数 (Foo)
1-2 Scope-Safe constructors

Calling a function constructor within the global scope, resulting in the addition of redundant properties at the global scope because no new is used

function Person(name,job) {    this.name = name    this.job = job}// 假如为使用 New 操作var person = Person('zhangsan','sell') console.log(window.name, window.job)    // zhangsan sellconsole.log(person.name, person.job)    // VM76:11 Uncaught TypeErrorr

This problem is caused by the late binding of the This object
Therefore, it is necessary to verify inside the function this对象是正确类型的实例 :

function Person(name){    if(this instanceof Person){        this.name = 'zhang';    } else {        return new Person(name)    }}var person = Person('zhang')console.log(window.name)    //  ''console.log(person.name)    //  zhang
1-3 Lazy Load function

Lazy loading indicates that the branch executed by the function is executed the first time the function is called, and in the first call, the function is overwritten as another function that is executed in the appropriate way, so that any calls to the original function will not be judged by the executing branch. (Saving calculation Power)

1-3-1 Application Scenarios

1. AJAX compatibility under different browsers
2, APP embedded H5 different environment under a function method, the wording is not the same
3, H5 in different platforms in many forms of expression because of a method and show the difference.

1-3-2 the place of attention

1, the more frequent application, the more can reflect the advantages of this model
2, fixed, a single decision, in a fixed application environment will not change
3, the complex branch judgment, no difference, do not need to apply this mode

1-3-3 Demo
const getCurEnv = () => {    // 当前环境为 chrome 浏览器环境    return window.navigator.userAgent.toLowerCase().match(/chrome/i) !== null}const Person = function(name) {    this.name = name}const http = {    created: function() {        if (getCurEnv()) {            console.log(this)            this.created = function() {                console.log('test1')                return new Person('zhang1')            }            console.log('test2')            return new Person('zhang2')        } else {            this.created = function() {                console.log('test3')                return new Person('zhang3')            }        }    },    Atest: ()=> {        console.log(this)    // window {}    },    Ftest: function() {        console.log(this)    // http {}    }}http.created()  // test2 Person {name: "zhang2"}http.created()  // test1 Person {name: "zhang1"}// 实际有效的 惰性载入函数 上面的 二个 方法返回的值 其实是一样的。这样惰性载入函数 才是真实有效。
1-4 function Bindings

This technique is often used in conjunction with callback functions and event handling to preserve the code execution environment while passing functions as variables

Many JavaScript libraries implement a function that binds a function to a specified environment, which is generally called bind (). A simple bind () function takes a function and an environment and returns a given function in the context of the given function, and passes all parameters intact. This function returns a closed packet.

The above language description is always very ethereal, we come to the demo directly:

1-4-1 Demo
var obj1 = {    name: 'zhang',    getName: function() {        console.log(arguments[0][2], 'obj1')        return this.name    }}var obj2 = {    name: 'lisi',    getName: function() {        console.log(arguments, 'obj2')        return this.name    }}function Bind(fn, context) {    return fn.call(context, arguments)}Bind(obj1.getName,obj2,'xxxxx') // Arguments [Arguments(3), callee: ƒ, Symbol(Symbol.iterator): ƒ] "obj1"// 'lisi'// 这里我们对于 arguments 的 理解和操作来说都是比较陌生,那么下面 我们再来介绍下// arguments 具体是什么。
1-4-2 arguments

Class Array (Array-like)

    • Each element can be accessed with subscript
    • Has the Length property
    • The arguments data type is Object
    • You can use the For and For-in methods
    • Does not have an Array native method

Demo

var test = function() {    console.log(arguments)    console.log(arguments[0])    console.log(arguments.length)    console.log(typeof arguments)    for(var i = 0; i<arguments.length; i++) {        var ele = arguments[i]        console.log(ele)    }    for(x in arguments) {        console.log(arguments[x])    }    // arguments.split(' ')    // Uncaught TypeError: arguments.split is not a function}test(1,2,3,4)// Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]// 1// 4// object// 1 2 3 4// 1 2 3 4

Convert an array of classes to arrays

    • Method One:
var test = function() {    console.log(arguments)    var arrArg = Array.prototype.slice.call(arguments)    console.log(arrArg)}test(1,2,3,4) // [1, 2, 3, 4]
    • Method Two:
var test = function() {    console.log(arguments)    var arrArg = Array.from(arguments)    console.log(arrArg)}test(1,2,3,4) // [1, 2, 3, 4]
1-4-3 ES5 The Central Plains Born bind () method detailed

The text is still difficult to explain, then we still showcode~.
Demo:

var obj = {    a: 1,    b: 2,    getCount: function(c, d) {        return this.a + this.b + c + d    }}console.log(obj.getCount(3,4))  // 10window.a = window.b = 0var funcs = obj.getCountfuncs(3,4)                      // 7

Bind is a function extension method that binds code to rebind the this point (obj) inside the func
Compatible with IE9 +
Demo:

var obj = {    a: 1,    b: 2,    getCount: function(c, d) {        return this.a + this.b + c + d    }}console.log(obj.getCount(3,4))  // 10window.a = window.b = 100var funcs = obj.getCount.bind(obj)funcs(3,4)          // 10// var funcs = obj.getCount.bind(window)// funcs(3,4)       // 207
1-5 function currying

Also called partial evaluation. The fact that the curry itself is a fixed parameter that can be expected and returns a specific function that handles batch-specific requirements.
This increases the applicability of the function, but also reduces the scope of application of the function.
The definition of words is always hard to accept, or showcode.
Demo: Suppose you want to write an accounting tool, then record the daily data, and finally count the whole week's data.
How?

let weekCost = 0const cost = function(num) {    weekCost += num }cost(100)   // 100cost(200)   // 300cost(300)   // 600
这个时候每天都会进行一次 总账,这个是我不想看到的,因为不想每天都被这个总账看着心痛,毕竟工资不够花是常态。我就希望每个星期给我来一次总账刺激。
const currying = function(fn) {    let args = []    return function() {        if (arguments.length == 0) {            return fn.apply(this, args)        } else {            let test = [].push.apply(args,arguments)            // return fn.call(this, arguments)        }    }}const costs = (function() {    let money = 0    return function() {        money = 0        for(let i = 0; i<arguments.length; i++) {            money += arguments[i]        }        return money    }})()let cost = currying(costs)cost(100)cost(100)cost(100)cost(100)cost(100)console.log(cost()) // 500cost(100)cost(100)console.log(cost()) // 700

Summary one:

上面的 dmeo 中,当调用 cost() 时,如果明确带上参数,表明此时并不进行真正的求值计算,而是把这些参数保存起来,此时让 cost() 函数返回另外一个函数。只有当我们以不带参数的形式执行 cost() 时,才利用前面保存的所有参数,真正开始求值计算。这是一个具象的函数颗粒化的方法。那么我们想把函数颗粒化抽象出来又需要怎么来概括呐? 下面的例子,我们再来看下这个颗粒化!

Demo

const currying = function(fn) {    let args = Array.prototype.slice.call(arguments, 1)    return function() {        let innerArgs = Array.prototype.slice.call(arguments)        return fn.apply(this, args.concat(innerArgs))    }}const add = function(n, m) {    return n + m}var curriedAdd = currying(add, 3)console.log(curriedAdd(5)) // 8

Summary two:

这个例子中,通过颗粒化 创建已经设置好了一个或多个参数的函数。后续还会有更多的例子,来证明这个点。

Attention

Either the curry function or the binding function brings additional overhead, so it should not be abused.

1-6 Inverse function currying

Conversely, the role of the anti-curry function in relation to the expansion of functions, so that the function as a function of a particular object can be used by arbitrary objects.

Core:

By using the Uncurrying function, a method that can be used only for an object is extended to more objects to be referenced.
ShowCode:

Function.prototype.uncurrying = function() {    var that = this;    return function() {        return Function.prototype.call.apply(that, arguments);    }}const test1 = {}const test2 = {} test1.sayHi = function () {    return "Hello " + this.value +" "+[].slice.call(arguments);}test2.sayHiuncurrying = test1.sayHi.uncurrying()console.log(test2.sayHiuncurrying({value:'world'},"hahaha"));// Hello world hahaha

The core code has been shown, carefully read the product read ~

Well, write it here today, the back will continue to improve the interpretation of the Demo, do not understand the message can be discussed ~

GitHub Address: (Welcome star, welcome recommendation:)

Front-end advanced techniques, high-order functions (I.)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.