How do I make a chain interface using constructor functions in Javascript?

I want a jQuery-like chaining interface . However, all of the prototypes of tutorials, conversations, jQuery source don't make it clear, so I really appreciate help in resolving this issue.

In jQuery, I can call jQuery ('. Apple'), but also jQuery.ajax ('param'), since jQuery seems to be a constructor function and so might have properties like the ajax function I assume?

What I want:

Postal('apple') // Return chain-able function/object/constructor thing
Postal('apple').send('China').fee(99) // Used like this 

Postal.send // should be undefined, need product-selector
Postal.area // should be function, accepting 1 parameter

Postal.area('Europe') // Use like this
Postal.area('Asia')

      

Note above: . The scope must be accessible for chained methods like send ()

The functions that the Global Accessory product selector can use:

Postal('apple').send('China').fee(9) // Apples to China fee
Postal('apple').fee(9) // Apples to anywhere default fee
Postal('orange').send('USA').fee(9) 

      

My attempt at solving this:

Comments around my approach to understand and simulate the jQuery source:

// # Assume
// ES2016 and not to much performance downsides or object allocations

//This should become our Globalisk-jQuery-Accessor
var Postal

// Create a non-global scope inside here
(function() {

    // Locals that are global for the postal-object-function
    var p_area           = 'global'
    var p_destination    = 'unknown'
    var p_product        = '<unknown product>'

    // our main selector, like: jQuery('.container')
    var postal = (product) => {
        // We use the same postal-object but create a new instance that can
        // handle initializations of something
        return new postal.prototype.init(product)
    }

    // All functions that only callable with a product-selector
    postal.prototype = {
        init: (product) => {
            console.log("Init ran "+product)
            // here we return this in case of no arguments?
            // should we return the base object with slightly different methods?
            if (!arguments[0]) {
                return this
            }

            // Make 'product' parameter local to this postal call but shared
            // amongst all chaining functions
            p_product = product // or?
        }
    }

    area = (area) => {
        p_area = area //Save for future calls
        console.log("Area set to: " + area)
        return
        // No return since no chaining possible after area is set
    }

    send = (destination) => {
        p_destination = destination //Save for future chaining
        console.log("Sending to " + destination + "...")
        return send
    }

    send.fee = function fee(amount) {
        console.log("Setting "+p_destination+" send fee to " + amount + " in " +
        p_area + " for product "+ p_product)
        return fee
    }

    // Set so new instance has same "properties" as postal has itself
    //Need something like this? postal.prototype.init.prototype = postal.prototype

    Postal = postal // Set our global accessor, from now on it should be const

})()

// Call direct function without going trough selector
console.log( Postal.send === undefined )

Postal.area('Europe') // Change the Postal-global "current area" state
Postal('apple').send('China').fee(99) // Applies only to "Europe"
Postal.area('Asia')
Postal('apple').send('China').fee(33)
Postal('orange').send('USA').fee(9)

      

Expected Result:

The code is assumed to be fixed to work as intended. I am working in node v5.3.0.

true
Area set to: Europe
init ran apple
Sending to China...
Setting China send fee to 99 in Europe for product apple
Area set to: Asia
Sending to China...
Setting China send fee to 33 in Asia for product apple
init ran orange
Sending to USA...
Setting USA send fee to 9 in Asia for product orange

      

It's easy to do this with two accessories like PostalCore.area () for global methods and Postal ("product here") for product selector-methods, so the gist of the question is how to do this with a constructor function to could have both on one object, for example jQuery does - I also welcome arguments, why not :)

+3


source to share





All Articles