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的编程范式借鉴了函数式编程的概念,从工程和实现角度向命令式妥协. 编程的领域里有三大流派:函数式.命令式.逻辑式. ...
随机推荐
- Redis基础一(Linux)
Redis概述 1.是一个开源的,先进的<key,value>存储,并用与构建高性能,可扩展的应用程序的完美解决方案 2.从它的许多竞争继承来的三个主要特点: l Redis数据库完全在 ...
- 给MongoDB添加索引
用过数据库的都知道,数据库索引与书籍的索引类似,都是用来帮助快速查找的. MongoDB的索引跟关系型数据库的索引几乎一致. 1. 索引的创建 mongodb采用ensureInd ...
- [原创]一款小巧、灵活的Java多线程爬虫框架(AiPa)
1.简介 AiPa 是一款小巧,灵活,扩展性高的多线程爬虫框架. AiPa 依赖当下最简单的HTML解析器Jsoup. AiPa 只需要使用者提供网址集合,即可在多线程下自动爬取,并对一些异常进行处理 ...
- 11 Django REST Framework 针对基于类的视图添加 @csrf_exempt
01-在类的 dispatch 方法上使用 @csrf_exempt from django.views.decorators.csrf import csrf_exempt class MyView ...
- OO第一单元总结——多项式求导
第一次作业分析 1.程序结构分析 类图: 好吧,这一次基本上完全是在面向过程编程,没有看出来任何的面向对象的特性. 复杂度: 可以看到模块间的相互耦合度很高,PolyDerive方法的非结构化程度也不 ...
- css 3 新特性
CSS3的新特性大致分为以下六类 1.CSS3选择器 2.CSS3边框与圆角 3.CSS3背景与渐变 4.CSS3过渡 5.CSS3变换 6.CSS3动画 下面分别说一说以上六类都有哪些内容 CSS3 ...
- Ubuntu系统桌面任务栏和启动器全部消失解决方案
ubuntu桌面上没有启动器,没有任务栏,只有一个背景,但是运行正常.这种情况很可能是文件管理程序出现异常了. 解决办法: Ctrl+Alt+F1 进入命令行,输入: sudo service lig ...
- MySQL之B+树索引(转自掘金小册 MySQL是怎样运行的,版权归作者所有!)
每个索引都对应一棵B+树,B+树分为好多层,最下边一层是叶子节点,其余的是内节点.所有用户记录都存储在B+树的叶子节点,所有目录项记录都存储在内节点. InnoDB存储引擎会自动为主键(如果没有它会自 ...
- Python——汇总
一.工具类 (1)pycharm激活.中文破解 (2)pycharm的基本设置 (3)pycharm常用包和插件的安装 二.数据类型 (1)列表.元祖.字典 操作方法 (2)迭代器操作方法 (3)生成 ...
- ES6 对象增强
对象字面量语法扩展: 1, 属性初始化语法简写:给一个属性赋一个变量值,如果变量名和属性名相同,可以省略变量名和冒号,直接写属性名,js引擎在执行代码的时候,自动查找 和属性命名相同的变量并赋值. l ...