你必須收藏的 ES6 語法密糖 – Spread Operator 技巧

當耐特發表於2019-01-08

→→→ 原文地址

Spread Operator 是我最喜歡的語法糖,沒有之一,在應用場景上也是最為廣泛,下面說下使用場景和技巧。

這是對應的 babel 外掛,當然直接使用 typescript 或者直接使用 omi-cli 已經內建了這個特性,可以直接使用。

不使用 Apply

apply 和 call 可以執行函式,改變 this 執行,比如:

function add(a, b){ 
return a + b
}複製程式碼

假設有個場景引數是以陣列的形式傳遞過來,傳統的做法是:

const args = [11, 12]add.apply(null, args)複製程式碼

或者

const args = [11, 12]add.call(null, args[0], args[1])複製程式碼

使用 Spread Operator 之後:

const args = [11, 12]add(...args)複製程式碼

babel 編譯後的結果:

function add(a, b) { 
return a + b;

}var args = [11, 12];
add.apply(undefined, args);
複製程式碼

常見的場景還有:

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]);
複製程式碼

把 arguments 或 NodeList 轉成陣列

[...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);
// 1console.log(y);
// 2console.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"]);
複製程式碼

Spread 實戰

react useomi use

 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 中沒有加入類似的功能。

Omi extractclass

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 上。

Omiu button 實戰

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>
)
}
})複製程式碼

extractClass 原始碼

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,真實無處不在。

參考文件

來源:https://juejin.im/post/5c340756e51d45523070f877

相關文章