ES2015 中的函数式Mixin
原文链接:http://raganwald.com/2015/06/17/functional-mixins.html
在“原型即对象”中,我们看到可以对原型使用 Object.assign 来模拟 mixin,原型是 JavaScript 中类概念的基石。现在我们将回顾这个概念,并进一步探究如何将功能糅合进类。
首先,简单回顾一下:在 JavaScript 中,类是通过一个构造函数和它的原型来定义的,无论你是用 ES5 语法,还是使用 class 关键字。类的实例是通过 new 调用构造器的方式创建的。实例从构造器的 prototype 属性上继承共享的方法。
对象 mixin 模式
class Todo {
constructor (name) {
this.name = name || 'Untitled';
this.done = false;
}
do () {
this.done = true;
return this;
}
undo () {
this.done = false;
return this;
}
}
const Coloured = {
setColourRGB ({r, g, b}) {
this.colourCode = {r, g, b};
return this;
},
getColourRGB () {
return this.colourCode;
}
};
Object.assign(Todo.prototype, Coloured);
new Todo('test')
.setColourRGB({r: 1, g: 2, b: 3})
//=> {"name":"test","done":false,"colourCode":{"r":1,"g":2,"b":3}}
const colourCode = Symbol("colourCode");
const Coloured = {
setColourRGB ({r, g, b}) {
this[colourCode]= {r, g, b};
return this;
},
getColourRGB () {
return this[colourCode];
}
};
函数式 mixin
const Coloured = (target) =>
Object.assign(target, {
setColourRGB ({r, g, b}) {
this.colourCode = {r, g, b};
return this;
},
getColourRGB () {
return this.colourCode;
}
}); Coloured(Todo.prototype);
const FunctionalMixin = (behaviour) =>
target => Object.assign(target, behaviour);
const Coloured = FunctionalMixin({
setColourRGB ({r, g, b}) {
this.colourCode = {r, g, b};
return this;
},
getColourRGB () {
return this.colourCode;
}
});
可枚举性
Coloured(Todo.prototype)
const urgent = new Todo("finish blog post");
urgent.setColourRGB({r: 256, g: 0, b: 0});
for (let property in urgent) console.log(property);
// =>
name
done
colourCode
setColourRGB
getColourRGB
const FunctionalMixin = (behaviour) =>
function (target) {
for (let property of Reflect.ownKeys(behaviour))
Object.defineProperty(target, property, { value: behaviour[property] })
return target;
}
mixin 的职责
class Todo {
constructor (name) {
this.name = name || Todo.DEFAULT_NAME;
this.done = false;
}
do () {
this.done = true;
return this;
}
undo () {
this.done = false;
return this;
}
}
Todo.DEFAULT_NAME = 'Untitled';
// If we are sticklers for read-only constants, we could write:
// Object.defineProperty(Todo, 'DEFAULT_NAME', {value: 'Untitled'});
const shared = Symbol("shared");
function FunctionalMixin (behaviour) {
const instanceKeys = Reflect.ownKeys(behaviour)
.filter(key => key !== shared);
const sharedBehaviour = behaviour[shared] || {};
const sharedKeys = Reflect.ownKeys(sharedBehaviour);
function mixin (target) {
for (let property of instanceKeys)
Object.defineProperty(target, property, { value: behaviour[property] });
return target;
}
for (let property of sharedKeys)
Object.defineProperty(mixin, property, {
value: sharedBehaviour[property],
enumerable: sharedBehaviour.propertyIsEnumerable(property)
});
return mixin;
}
FunctionalMixin.shared = shared;
const Coloured = FunctionalMixin({
setColourRGB ({r, g, b}) {
this.colourCode = {r, g, b};
return this;
},
getColourRGB () {
return this.colourCode;
},
[FunctionalMixin.shared]: {
RED: { r: 255, g: 0, b: 0 },
GREEN: { r: 0, g: 255, b: 0 },
BLUE: { r: 0, g: 0, b: 255 },
}
});
Coloured(Todo.prototype)
const urgent = new Todo("finish blog post");
urgent.setColourRGB(Coloured.RED);
urgent.getColourRGB()
//=> {"r":255,"g":0,"b":0}
mixin 本身的方法
urgent instanceof Todo
//=> true urgent instanceof Coloured
//=> false
Object.defineProperty(Coloured, Symbol.hasInstance, {value: (instance) => true});
urgent instanceof Coloured
//=> true
{} instanceof Coloured
//=> true
const shared = Symbol("shared");
function FunctionalMixin (behaviour) {
const instanceKeys = Reflect.ownKeys(behaviour)
.filter(key => key !== shared);
const sharedBehaviour = behaviour[shared] || {};
const sharedKeys = Reflect.ownKeys(sharedBehaviour);
const typeTag = Symbol("isA");
function mixin (target) {
for (let property of instanceKeys)
Object.defineProperty(target, property, { value: behaviour[property] });
target[typeTag] = true;
return target;
}
for (let property of sharedKeys)
Object.defineProperty(mixin, property, {
value: sharedBehaviour[property],
enumerable: sharedBehaviour.propertyIsEnumerable(property)
});
Object.defineProperty(mixin, Symbol.hasInstance, {value: (instance) => !!instance[typeTag]});
return mixin;
}
FunctionalMixin.shared = shared;
urgent instanceof Coloured
//=> true
{} instanceof Coloured
//=> false
总结
ES2015 中的函数式Mixin的更多相关文章
- C++学习35 模板中的函数式参数
C++对模板类的支持比较灵活,模板类的参数中除了可以有类型参数,还可以有普通参数.例如: template<typename T, int N> class Demo{ }; N 是一个普 ...
- 可爱的 Python : Python中的函数式编程,第三部分
英文原文:Charming Python: Functional programming in Python, Part 3,翻译:开源中国 摘要: 作者David Mertz在其文章<可爱的 ...
- Java 中的函数式编程(Functional Programming):Lambda 初识
Java 8 发布带来的一个主要特性就是对函数式编程的支持. 而 Lambda 表达式就是一个新的并且很重要的一个概念. 它提供了一个简单并且很简洁的编码方式. 首先从几个简单的 Lambda 表达式 ...
- C#中的函数式编程:序言(一)
学了那么久的函数式编程语言,一直想写一些相关的文章.经过一段时间的考虑,我决定开这个坑. 至于为什么选择C#,在我看来,编程语言分三类:一类是难以进行函数式编程的语言,这类语言包括Java6.C语言等 ...
- java基础---->java8中的函数式接口
这里面简单的讲一下java8中的函数式接口,Function.Consumer.Predicate和Supplier. 函数式接口例子 一.Function:接受参数,有返回参数 package co ...
- (数据科学学习手札48)Scala中的函数式编程
一.简介 Scala作为一门函数式编程与面向对象完美结合的语言,函数式编程部分也有其独到之处,本文就将针对Scala中关于函数式编程的一些常用基本内容进行介绍: 二.在Scala中定义函数 2.1 定 ...
- ES2015中的解构赋值
ES2015中允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,被称为”解构(Destructering)“. 以前,为变量赋值,只能指定值. /** * 以前,为变量赋值,只能直接指定值 * ...
- ES2015中let的暂时性死区(TDZ)
Tomporal Dead Zone (TDZ)是ES2015中对作用域新的专用定义.是对于某些遇到在区块作用域绑定早于声明语句时的情况.Tomporal Dead Zone (TDZ)可以理解为时间 ...
- Apache Beam中的函数式编程理念
不多说,直接上干货! Apache Beam中的函数式编程理念 Apache Beam的编程范式借鉴了函数式编程的概念,从工程和实现角度向命令式妥协. 编程的领域里有三大流派:函数式.命令式.逻辑式. ...
随机推荐
- [RHEL 7]ISCSI服务端及客户端连接配置
环境RHEL7.4 1.搭建服务器端主机环境 网络配置 网卡eth0 10.0.0.1 网卡eth1 10.1.0.1 网卡eth2 10.2.0.1 网卡eth3 10.3.0.1 硬盘配置 添加一 ...
- LeetCode算法题-Largest Number At Least Twice of Others(Java实现)
这是悦乐书的第308次更新,第328篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第177题(顺位题号是747).在给定的整数数组中,总有一个最大的元素.查找数组中的最大 ...
- docker 发布方式尝试
docker 发布方式尝试 目前有个小项目, 尝试用docker的方式来发布, 项目只有一个节点, 使用 kubenate 有点小题大做, 所以采用docker-compose来发布. 发布过程 GI ...
- oracle知识点总结基础篇1
最近学习了Oracle,对学习内容挑干的进行总结! 1.准备工作:学习Oracle首先就是安装环境.我装的是oracle11g. 2.安装完成之后在dos窗口中,输入 sqlplus 再输入用户名和 ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
- python开发之路-LuffyCity
阅读目录 一.python基础语法 二.python基础之字符编码 三.python基础之文件操作 四.python基础小练习 五.python之函数基础 六.python之函数对象.函数嵌套.名称空 ...
- 四。Hibernate 使用MAVEN工具
maven工具的使用1.作用:打包项目以及jar包的版本管理2.使用步骤: a.下载maven工具,修改conf目录下的setting.xml文件 <mirror> <id>a ...
- Web后台快速开发框架
Web后台快速开发框架 Coldairarrow 目录 目录 第1章 目录 1 第2章 简介 3 第3章 基础准备 4 3.1 开发环境要求 4 3.2 ...
- 不能完整读取txt文件问题
txt文件内容 5 1.3 0.4 3.4 -1.7 16.7 0.89 14.17 4.8 1.34 0.42 3.36 -2 16.2 0.9 14.8 4.9 1.30 0.37 3.51 -1 ...
- 小程序 canvas画本 地图片
ctx.drawImage('../../../../page/home/resources/pic/che_logo.png', 10, 435, 50,50); 本地图片要根路径