Allow variadic arguments to m.fragment (#2328)
* Implement support for variadic arguments to `m.fragment` While I was at it, I refactored the common logic out of `hyperscript`. * Add a missed change from #2326 * Update docs + changelog [skip ci] * Explain rationale for `hyperscriptVnode`'s calling convention This way, it doesn't get erroneously "cleaned up" into something worse, and so it's clearer how it'd be potentially optimized once ES5 support is dropped.
This commit is contained in:
parent
843f420291
commit
966e78bcab
8 changed files with 256 additions and 43 deletions
53
render/hyperscriptVnode.js
Normal file
53
render/hyperscriptVnode.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
"use strict"
|
||||
|
||||
var Vnode = require("../render/vnode")
|
||||
|
||||
// Call via `hyperscriptVnode.apply(startOffset, arguments)`
|
||||
//
|
||||
// The reason I do it this way, forwarding the arguments and passing the start
|
||||
// offset in `this`, is so I don't have to create a temporary array in a
|
||||
// performance-critical path.
|
||||
//
|
||||
// In native ES6, I'd instead add a final `...args` parameter to the
|
||||
// `hyperscript` and `fragment` factories and define this as
|
||||
// `hyperscriptVnode(...args)`, since modern engines do optimize that away. But
|
||||
// ES5 (what Mithril requires thanks to IE support) doesn't give me that luxury,
|
||||
// and engines aren't nearly intelligent enough to do either of these:
|
||||
//
|
||||
// 1. Elide the allocation for `[].slice.call(arguments, 1)` when it's passed to
|
||||
// another function only to be indexed.
|
||||
// 2. Elide an `arguments` allocation when it's passed to any function other
|
||||
// than `Function.prototype.apply` or `Reflect.apply`.
|
||||
//
|
||||
// In ES6, it'd probably look closer to this (I'd need to profile it, though):
|
||||
// module.exports = function(attrs, ...children) {
|
||||
// if (attrs == null || typeof attrs === "object" && attrs.tag == null && !Array.isArray(attrs)) {
|
||||
// if (children.length === 1 && Array.isArray(children[0])) children = children[0]
|
||||
// } else {
|
||||
// children = children.length === 0 && Array.isArray(attrs) ? attrs : [attrs, ...children]
|
||||
// attrs = undefined
|
||||
// }
|
||||
//
|
||||
// if (attrs == null) attrs = {}
|
||||
// return Vnode("", attrs.key, attrs, children)
|
||||
// }
|
||||
module.exports = function() {
|
||||
var attrs = arguments[this], start = this + 1, children
|
||||
|
||||
if (attrs == null) {
|
||||
attrs = {}
|
||||
} else if (typeof attrs !== "object" || attrs.tag != null || Array.isArray(attrs)) {
|
||||
attrs = {}
|
||||
start = this
|
||||
}
|
||||
|
||||
if (arguments.length === start + 1) {
|
||||
children = arguments[start]
|
||||
if (!Array.isArray(children)) children = [children]
|
||||
} else {
|
||||
children = []
|
||||
while (start < arguments.length) children.push(arguments[start++])
|
||||
}
|
||||
|
||||
return Vnode("", attrs.key, attrs, children)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue