3

I want an chain-able interface similar to jQuery. Still all prototype tutorials, talks, jQuery source is not making this clear, so much appreciate help in solving this.

In jQuery I can call jQuery('.apple') but also jQuery.ajax('param') since jQuery seems to be a constructor function, and therefore can have properties such as 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 Area should be accessible for chain-methods such as send()

Functions that can use the "Global Accessor" product selector:

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 it:

Comments is around my approach to understand and mimic jQuery's 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 output:

Assuming code is fixed to work as intended. I am running 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

This is easy to accomplish with two accessors such as: PostalCore.area() for global-methods and Postal('product here') for product-selector-methods, so the essence of the question is really how to do this with a constructor function so one can have both on same object, like jQuery does - I also welcome arguments to why not :)

Veon
  • 41
  • 4
  • 1
    First of all, I'd recommend not to let [the jQuery `prototype.init` pattern](https://stackoverflow.com/a/12143833/1048572) inspire you. Drop all that and start with a normal constructor function. Do not mimic the jQuery source. – Bergi Jul 30 '17 at 17:10

0 Answers0