资讯专栏INFORMATION COLUMN

对比scala,用javascript实现 特质(trait) 的部分特性

cocopeak / 1250人阅读

摘要:特质是的一个重要的特性,主要的使用方式有两个方面拓宽瘦接口为胖接口。定义可堆叠的改变。相对于多重继承而言最灵活的一方面就是所指定的对象只有到被混入之后才能确定。

特质(trait)是scala的一个重要的特性,主要的使用方式有两个方面:1.拓宽瘦接口为胖接口。2.定义可堆叠的改变。
trait相对于多重继承而言最灵活的一方面就是super所指定的对象只有到被混入之后才能确定。
因为特质里面既可以有字段方法,还可以既只写方法的类型,也可以写上方法的实现(不像JAVA的接口那样),而且可以混入到类中,类也可以使用任意多的特质。相当的灵活。

就混入到类中,和胖瘦接口而言,对javascript来说简直就是天生的,不值一提(但javascript的问题是,以弱类型换来的灵活,有时候总感觉灵活的都不像话,特别不容易理解其他jser的代码)。

就[可堆叠的改变]而言:如下scala代码:

import scala.collection.mutable.ArrayBuffer

abstract class IntQueue {
    def get(): Int
    def put(x: Int)
}

class BasicIntQueue extends IntQueue {
    private val buf = new ArrayBuffer[Int]
    def get() = buf.remove(0)
    def put(x: Int) { buf += x }
}

// val queue = new BasicIntQueue
// queue.put(10)
// queue.put(20)
// queue.get()
// queue.get()

trait Doubling extends IntQueue {
    abstract override def put(x: Int) { super.put(2 * x) }
}

class MyQueue extends BasicIntQueue with Doubling
// val queue = new MyQueue
// queue.put(10)
// println(queue.get())
val queue = new BasicIntQueue with Doubling
// queue.put(10)
// println(queue.get())

trait Incrementing extends IntQueue {
    abstract override def put(x: Int) { super.put(x + 1) }
}

trait Filtering extends IntQueue {
    abstract override def put(x: Int) {
        if(x >= 0) super.put(x)
    }
}

val queue1 = new BasicIntQueue with Doubling with Incrementing with Filtering
queue1.put(-1)//先执行Filtering,-1 被过滤掉了
queue1.put(0) // 执行过滤,然后 +1,然后 *2
queue1.put(1)
println(queue1.get())
println(queue1.get())

javascript的实现:
代码链接:https://github.com/peichao01/test2/tree/master/javascript/trait

function trait (konstructor, traits) {
    traits = [].slice.call(arguments, 1);
    function _trait(reciever, trait_, parentName){
        for(var methodName in trait_){
            if(reciever.hasOwnProperty(methodName)){
                var method = trait_[methodName];
                if((typeof method == "function") && 
                    (typeof reciever[methodName] == "function") &&
                    (method.toString().indexOf(parentName) > -1)) {
                    var baseMethod = reciever[methodName];
                    reciever[methodName] = function(){
                        var baseSaved = this[parentName];
                        this[parentName] = baseMethod;
                        var result = method.apply(this, arguments);
                        this[parentName] = baseSaved;
                        return result;
                    };
                }
                else {
                    reciever[methodName] = method;
                }
            }
        }
    }
    function mixinTrait (reciever) {
        for(var i = 0, len = traits.length; i < len; i++){  
            _trait(reciever, traits[i], "super");
        }
    }
    function Constructor(){
        konstructor.apply(this, arguments);
        mixinTrait(this);
    }
    for(var key in konstructor.prototype){
        if(konstructor.prototype.hasOwnProperty(key)) Constructor.prototype[key] = konstructor.prototype[key];
    }
    mixinTrait(Constructor.prototype);
    return Constructor;
}

function BasicIntQueue(name){
    this.name = name;
    this._buf = [];
}
BasicIntQueue.prototype.get = function(){
    return this._buf.shift();
};
BasicIntQueue.prototype.put = function(x){
    this._buf.push(x);
};
function BasicIntQueue2(name){
    this.name = name;
    this._buf = [];

    this.get = function(){
        return this._buf.shift();
    };

    this.put = function(x){
        this._buf.push(x);
    };
}

var trait_Doubling = {
    put: function(x){
        this.super(2 * x);
    }
};
var trait_Incrementing = {
    put: function(x){
        this.super(x + 1);
    }
};
var trait_Filtering = {
    put: function(x){
        if(x >= 0) this.super(x);
    }
};

var Klass = trait(BasicIntQueue2, trait_Doubling, trait_Incrementing, trait_Filtering);
var queue = new Klass("Klass");
var queue1 = new BasicIntQueue("BasicIntQueue");

queue1.put(-1);

queue.put(-1);
queue.put(0);
queue.put(1);

console.log(queue.get()); // 2
console.log(queue.get()); // 4
console.log(queue.get()); // undefined

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78052.html

相关文章

  • 函数式编程与面向对象编程[4]:Scala类型关联Type Alias

    摘要:函数式编程与面向对象编程的类型关联之剑目录类型关联关键字里的类型,除了在定义时会产生类型,还可以通过关键字来声明类型。复合类型与关键字这种形式的类型称为复合类型或者也叫交集类型。 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias 之剑 2016.5.4 23:55:19 类型关联 Type Alias type关键字 scala里的类型,除了在定义clas...

    wupengyu 评论0 收藏0
  • Java 8 vs. Scala(一): Lambda表达式

    摘要:编程语言将函数作为一等公民,函数可以被作为参数或者返回值传递,因为它被视为对象。是表示已注释接口是函数接口的注释。如果一个函数有一个或多个参数并且有返回值呢为了解决这个问题,提供了一系列通用函数接口,在包里。 【编者按】虽然 Java 深得大量开发者喜爱,但是对比其他现代编程语言,其语法确实略显冗长。但是通过 Java8,直接利用 lambda 表达式就能编写出既可读又简洁的代码。作者...

    yuanxin 评论0 收藏0
  • 函数范式入门(什么是函数式编程)

    摘要:第一节函数式范式什么是函数式编程函数式编程英语或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。 第一节 函数式范式 1. 什么是函数式编程 函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对...

    StonePanda 评论0 收藏0
  • 【Laravel】Laravel 框架关键技术解析·读书笔记(一)

    摘要:判断是否存在构造函数,不存在直接实例化,存在则通过来获取输入函数,并有相应的方法解决依赖参数问题,实现依赖注入。 Laravel 框架关键技术解析·读书笔记(一) 第一章 入口文件 请求访问的入口文件,主要完成几部分工作,分别是: 自动加载函数的添加 服务器实例化与服务注册 路由加载 请求实例化与路由分发 相应生成与发送 其中,自动加载函数用于包含引用文件,改文件是composer...

    CocoaChina 评论0 收藏0
  • Java 8 vs. Scala(二):Stream vs. Collection

    摘要:比如对一个数据流进行过滤映射以及求和运算,通过使用延后机制,那么所有操作只要遍历一次,从而减少中间调用。这里需知道中的元素都是延迟计算的,正因为此,能够计算无限数据流。 【编者按】在之前文章中,我们介绍了 Java 8和Scala的Lambda表达式对比。在本文,将进行 Hussachai Puripunpinyo Java 和 Scala 对比三部曲的第二部分,主要关注 Stream...

    GeekGhc 评论0 收藏0

发表评论

0条评论

cocopeak

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<