您的位置:首页 > Web前端 > JavaScript

[Javascript] Decorators in JavaScript

2016-06-14 03:10 309 查看
First, what is 'High Order function', basic just a function, inside the function return another fuction.

// High order fucntion

function fn() {
return function(){

}
}


For example:

function compose(a, b) {
return function(c){
return a(b(c));
}
}

function addTwo(val){
return val + 2;
}

function tiemsTwo(val){
return val * 2;
}

const val = compose(addTwo, tiemsTwo)(50);
console.info(val); // 102


Decorators is a subset of high order fucntion:

function fluent(fn){
return function(...args){
fn.apply(this, args);
return this;
}
}

function Person(){}

Person.prototype.setName = fluent(function(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
})

Person.prototype.getName = fluent(function(){
console.log(this.firstName + ' ' + this.lastName);
})

var p = new Person();

console.log( p.setName('John', 'Kent').getName());


In this code, fluent actually decorate Person class, make it chainable.

But In ES6:

class Person {
setName(f, l) {
this.firstName = f;
this.lastName = l;
}

getName() {
console.log(this.firstName, this.lastName);
}
}


We have no way to wrap setName and getName fucntion in fluent(). So that's way decorator comes in.

To use decorator to descorate a function in class:

function decorate(target, keys, descriptor){
var fn = descriptor.value;

// Overwrite the value, which in this case is function
descriptor.value = function(...args){
fn.apply(target, args);
return target;
}
}

class Person {

@decorate
setName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

@decorate
getName(){
console.log(this.firstName, this.lastName);
}
}

const p = new Person();
console.log(p.setName("Wan", "Zhentian").getName());


And it would be nice to reuse the fluent function:

function fluent(fn){
return function(...args){
fn.apply(this, args);
return this;
}
}


So we can do:

function fluent(fn){
return function(...args){
fn.apply(this, args);
return this;
}
}

function decorateWith(fn){
return (target, keys, descriptor) => {
// fn here refers to setName or getName
// fn should be call with in target context, which means Person{}
// the second argument in call() is function to be passed into fluent() function

descriptor.value = fn.call(target, descriptor.value);
}
}

class Person {

@decorateWith(fluent)
setName(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

@decorateWith(fluent)
getName(){
console.log(this.firstName, this.lastName);
}
}

const p = new Person();
console.log(p.setName("Wan", "Zhentian").getName());


[Note]: call(context, arguement, arguement, ....); here arguement is sinlge value

apply(context, arguements): here arguements is array
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: