→→→ 原文地址 css
Spread Operator 是我最喜欢的语法糖,没有之一,在应用场景上也是最为普遍,下面说下使用场景和技巧。html
这是对应的 babel 插件,固然直接使用 typescript 或者直接使用 omi-cli 已经内置了这个特性,能够直接使用。react
apply 和 call 能够执行函数,改变 this 执行,好比:git
function add(a, b){
return a + b
}
复制代码
假设有个场景参数是以数组的形式传递过来,传统的作法是:github
const args = [11, 12]
add.apply(null, args)
复制代码
或者typescript
const args = [11, 12]
add.call(null, args[0], args[1])
复制代码
使用 Spread Operator 以后:数组
const args = [11, 12]
add(...args)
复制代码
babel 编译后的结果:babel
function add(a, b) {
return a + b;
}
var args = [11, 12];
add.apply(undefined, args);
复制代码
常见的场景还有:app
const arr = [1, 2, 3, 4, 5]
Math.min(...arr) //求最小值
Math.max(...arr) //求最大值
复制代码
babel 编译后的结果:函数
var arr = [1, 2, 3, 4, 5];
Math.min.apply(Math, arr); //求最小值
Math.max.apply(Math, arr); //求最大值
复制代码
由于 Math.min 和 Math.max 参数个数是不限制的,因此这种场景很是适合使用 Spread Operator 。
先看下 array push 的语法:
array.push(item1, item2, ...., item3)
复制代码
能够看到 push 接收的参数也是不定,因此能够利用其实现合并数组功能:
arr1.push(...arr2)
复制代码
或者合并到前方:
arr1.unshift(...arr2)
复制代码
也能够直接声明式合并:
const arr1 = [2, 3]
const arr2 = [1, ...arr1, 4] //arr2 至关于 [1, 2, 3, 4]
复制代码
在好比:
const a = [1, 2]
a.push(...[3, 4, 5]) //[1,2,3,4,5]
复制代码
babel 编译后:
var a = [1, 2];
a.push.apply(a, [3, 4, 5]);
复制代码
[...document.querySelectorAll('div')]
复制代码
bebel 编译后:
function _toConsumableArray(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i];
}
return arr2;
} else {
return Array.from(arr);
}
}
[].concat(_toConsumableArray(document.querySelectorAll('div')));
复制代码
直接把 arguments 转成数组:
var myFn = function(...args) {
console.log(args.forEach) //ƒ forEach() { [native code] }
console.log(arguments.forEach) //undefined
}
myFn()
复制代码
babel 编译后:
var myFn = function myFn() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
console.log(args.forEach); //ƒ forEach() { [native code] }
console.log(arguments.forEach); //undefined
};
myFn();
复制代码
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
console.log(x); // 1
console.log(y); // 2
console.log(z); // { a: 3, b: 4 }
复制代码
babel 编译后:
function _objectWithoutProperties(obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
}
var _x$y$a$b = { x: 1, y: 2, a: 3, b: 4 },
x = _x$y$a$b.x,
y = _x$y$a$b.y,
z = _objectWithoutProperties(_x$y$a$b, ["x", "y"]);
复制代码
return [list, {
set,
push: (entry) => set([...list, entry]),
filter: (fn) => set(list.filter(fn)),
sort: (fn?) => set([...list].sort(fn)),
}];
};
复制代码
<button onClick={() => setItems([...items, { text: 'new item' }])}>
add
</button>
<button onClick={() => setItems([])}>empty</button>
复制代码
固然我自身不喜欢这种方式定义组件,因此在 omio 中没有加入相似的功能。
import { classNames, extractClass } from 'omi'
define('my-element', class extends WeElement {
render(props) {
//extractClass will take out this class/className from props and merge the other classNames to obj
const cls = extractClass(props, 'o-my-class', {
'other-class': true,
'other-class-b': this.xxx === 1
})
return (
<div {...cls} {...props}> Test </div>
)
}
})
复制代码
extractClass
简直是写 UI 组件的神器,该方法会提取出 props 的 class 或者 className,而且进行相似 classNames 库的合并。最后经过扩展运算符增长到 JSX 上。
import { define, WeElement, extractClass } from 'omi'
import css from './_index.css'
define('o-button', class extends WeElement {
static defaultProps = {
disabled: false,
type: 'primary',
size: 'normal'
}
css() {
return css
}
render(props) {
//提取 class,并从 props 中去掉
let cls = extractClass(props) || {}
const {
component,
type,
size,
plain,
children,
...others
} = this.props
const Component = component
? component
: this.props.href || type === 'vcode'
? 'a'
: 'button'
cls =
type === 'vcode'
? extractClass(cls, 'weui-vcode-btn')
: extractClass(cls, {
'weui-btn': true,
'weui-btn_mini': size === 'small',
'weui-btn_primary': type === 'primary' && !plain,
'weui-btn_default': type === 'default' && !plain,
'weui-btn_warn': type === 'warn',
'weui-btn_plain-primary': type === 'primary' && plain,
'weui-btn_plain-default': type === 'default' && plain,
'weui-btn_disabled': this.props.disabled && !plain,
'weui-btn_plain-disabled': this.props.disabled && plain
})
return (
<Component {...others} {...cls}> {children} </Component>
)
}
})
复制代码
export function extractClass() {
//提取第一个参数 props 和剩余的 args
const [props, ...args] = Array.prototype.slice.call(arguments, 0)
if (props.class) {
args.unshift(props.class)
delete props.class
} else if (props.className) {
args.unshift(props.className)
delete props.className
}
if (args.length > 0) {
return { class: classNames.apply(null, args) }
}
}
复制代码
能够看到 extractClass 自己也用到了 Spread Operator,真实无处不在。