Как сделать цепной интерфейс, используя функции конструктора в Javascript?
Я хочу цепной интерфейс, похожий на jQuery. Тем не менее, все учебные пособия по прототипам, доклады, исходные коды jQuery не проясняют этого, поэтому очень ценю помощь в решении этой проблемы.
В jQuery я могу вызывать jQuery('. Apple'), но также jQuery.ajax('param'), так как jQuery кажется функцией конструктора и, следовательно, может иметь свойства, такие как предполагаемая функция ajax?
Что я хочу:
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')
Примечание выше: область должна быть доступна для цепных методов, таких как send()
Функции, которые могут использовать селектор продукта "Global Accessor":
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)
Моя попытка решить это:
Комментарии касаются моего подхода к пониманию и подражанию источнику jQuery:
// # 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)
Ожидаемый результат:
Предполагая, что код исправлен, чтобы работать как задумано. Я работаю в узле 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
Это легко сделать с помощью двух методов доступа, таких как: PostalCore.area() для global-методов и Postal("продукт здесь") для методов выбора продуктов, поэтому суть вопроса заключается в том, как это сделать с помощью конструктора. функция, так что можно иметь оба на одном объекте, как это делает jQuery - я также приветствую аргументы почему бы и нет:)