什么是decorator
decorator是ES6的一個(gè)新特性,可以修改class的屬性
@test
class Person {
//do something
}
function test(tartget){
traget.prototype.name = 'xiaoming';
traget.prototype.sayName = function (){console.log(this.name)}
}
var p = new Person();
p.sayName(); //'xiaoming'
通過decorator,這樣就可以做到一個(gè)類的優(yōu)雅嵌套
多個(gè)decorator
@test1
@test2
@test3
@test4
class Person {
//do something
}
實(shí)際上多個(gè)decorator會(huì)從上到下依次進(jìn)入函數(shù),然后再從下往上依次執(zhí)行。想象一下高階組件的嵌套可能會(huì)比較好理解一些
優(yōu)化React代碼
實(shí)際上根據(jù)它的用法,我們可以聯(lián)想到React高階組件
//往往我們習(xí)慣于這樣去寫高階組件,但是一旦高階組件多,則會(huì)引起書寫的不美觀
class MyComponent extends React.Component{
}
export default withRoute(connect(MyComponent))
//實(shí)際上我們可以這么寫
@withRoute
@connect
export default class MyComponent extends React.Component{
}
而且修飾器不僅用于class,我們還可以用于類里面的方法
@withRoute
export default class MyComponent extends React.Component{
constructor() {
//將組件的this綁定給函數(shù)
this.handleClick = this.handleClick.bind(this)
}
@log
handleClick() {
}
}
function log(target, name, descriptor) {
const oldValue = descriptor.value;
const obj = { ...descriptor };
obj.value = function (...arg) {
const result = oldValue.apply(this, arg);
console.log(`name: ${name} arg: ${arg} target:${JSON.stringify(target)} oldValue:${oldValue} value:${JSON.stringify(result)}`);
return result;
};
return obj;
}
這里我們用組件示例,該方法可以使得每次觸發(fā)handleClick時(shí)都可以打印出信息。但是如果細(xì)心的朋友就會(huì)注意到,我們的handleClick并不是用箭頭函數(shù)寫的。這里也是值得注意的一點(diǎn),修飾器不能直接修飾箭頭函數(shù)或者匿名函數(shù),盡管這是類的方法。原因是因?yàn)楹瘮?shù)會(huì)存在提升,實(shí)際代碼如下
export default class MyComponent extends React.Component{
@log
handleClick = () => {
}
}
export default class MyComponent extends React.Component{
@log
handleClick = function () {
}
}
//以上兩種方法都不可以使用修飾器
export default class MyComponent extends React.Component{
@log
this.handleClick;
handleClick = () => {
}
}
Decorator用在react上的奇淫技巧
實(shí)際上我們可以自定義所有組件
// MyReact.js
import React from 'react';
export default function myComponet(target) {
Object.setPrototypeOf(target, React.Component);
// B 的實(shí)例繼承 A 的實(shí)例
Object.setPrototypeOf(target.prototype, React.Component.prototype);
return target;
}
// page.js
import myComponent from './MyReact'
@myComponent
class Page {
render(){
return <p>我是組件<p>
}
}
這樣做的好處就是,我們可以在所有的組件里面添加自己的一些東西。比如埋點(diǎn)。當(dāng)然,其實(shí)不使用修飾器其實(shí)也可以做到這點(diǎn),但是這種寫法會(huì)更為簡潔。
現(xiàn)在可以使用該語法嗎
實(shí)際上這還只是個(gè)提案,babel對(duì)這個(gè)需要安裝特殊的插件才可以支持轉(zhuǎn)義該語法babel-plugin-transform-decortors-legacy。因此在使用該語法的時(shí)候,可能還需要慎重選擇。如果要調(diào)試修飾器這個(gè)語法,我只能推薦,先去Babel轉(zhuǎn)義成ES5語法,然后再在chrome上調(diào)試。轉(zhuǎn)譯時(shí)記得添加babel-plugin-transform-decortors-legacy這個(gè)插件即可

后話
關(guān)于用decorate優(yōu)化react就到這了。利用修飾器造輪子實(shí)際上也是很有藝術(shù)的一件事。
最后,我們都需要努力