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的编程范式借鉴了函数式编程的概念,从工程和实现角度向命令式妥协. 编程的领域里有三大流派:函数式.命令式.逻辑式. ...
随机推荐
- mysql基本操作(1)
1.mysql数据库客户端安装 brew install mysql-client 2.mysql 连接数据库 mysql -h <数据库地址> -P <端口> -u < ...
- Python encode和decode
今天在写一个StringIO.write(int)示例时思维那么一发散就拐到了字符集的问题上,顺手搜索一发,除了极少数以外,绝大多数中文博客都解释的惨不忍睹,再鉴于被此问题在oracle的字符集体系中 ...
- MyBatis学习日记(一):拜见小主——MyBatis
近日学习MyBatis,特将学习过程及一点心得记录于此. MyBatis为何物? MyBatis 是支持定制化SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC ...
- python+selenium运行时,提示元素不可见
python+selenium运行多次新增项目脚本(出错的元素通过by_id的方式定位),当第三次新增时报Message: element not visible的错误,加入等待时间,等页面加载完成, ...
- Golang 入门 : 打造开发环境
工欲善其事,必先利其器!在学习和使用 Golang 时如果有一款得心应手的 IDE,相信一定可以事半功倍.虽然很多 IDE 都提供了对 Golang 的支持,但真正好用的没几个.VSCode 算是不错 ...
- 以API方式调用C# dll,使用OneNote2013 sp1实现OCR识别本地图片
http://www.cnblogs.com/Charltsing/p/OneNoteOCRAPI.html OneNote2013 OCR API调用使用说明2019.4.17 使用说明:1.安装干 ...
- css之图片下方定位遮掩层
需要的效果如图,图片下方加个遮掩层: html: <div class="listContent"> <div><img src="imag ...
- c++使用cmake创建dpdk项目
使用cmake创建dpdk 特别注意的时,链接dpdk库时,一定要使用 -Wl,--whole-archive 和 -Wl,--no-whole-archive 包含所有的静态库,注意,不要链接 li ...
- Activiti6-TaskService(学习笔记)重要
任务管理服务: 可以看出来,TaskService操作对象,主要针对于UserTask, 对于业务方来说,最重要的就是用户任务,可以对用户任务进行增删改查的管理.可以对相关流程的控制.也可以设置一些用 ...
- gRPC 如何使用python表示多维数组
在使用gRPC作为远程调用框架时,如何使用python来表示多维数组呢?gRPC中定义proto文件时,有一个参数是repeated,用来表示重复的数据类型,使用这个参数可以表示list类型.如下,我 ...