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