Object.defineProperty如何在AS3中?

时间:2013-02-14 19:20:46

标签: actionscript-3 unit-testing porting assertions should.js

我是一名强大的JavaScript背景的架构师,但我过去曾做过一些.NET和Java。

但是,我想把手放在ActionScript3上,我承诺这与JavaScript非常相关。

作为一个启动项目,我自己尝试将ActionScript3移植到我最喜欢的断言工具之一 - should.js - 这使得您的测试代码非常适合阅读。

更新时间:2013-02-19

我看到我对我的抽象发言感到困惑,所以我用一些具体问题替换了一些帖子。 这是完整的图片:

考虑以下JavaScript代码:

Object.defineProperty(Object.prototype, 'should'
, { set: function(){}
  , get: 
    function(){
       return new Assertion(Object(this).valueOf());
    }
  , configurable: true
  , enumerable  : false
  }
);

这是JavaScript模块Should的实现的一部分。另一部分是类Assertion的定义,它是用值构造的,并且针对该值实现了一组广泛且好的断言方法。像

这样的方法
var o = Assertion(actualValue)
o.equals(expectedValue1)
o.moreThan(expectedValue2)
o.contains(expectedValue3)

和别名以保留英语语法

var o = Assertion(actualValue)
o.equal(expectedValue1)
o.contain(expectedValue3)

和懒惰神枪手的别名,如

o.eql(expectedValue)
o.gt(expectedValue) //greater then
o.gte(...) //greater then or equal
//and so on... 

和一些只返回this的连接符(使用测试值构造的Assertion的实例),如

o.be
o.and

它给你什么?

看起来像这样的测试代码:

var person = getPerson();
Should.exist(person); //that's a static call, and that's easy

//but these are a member calls:
person.should.have("name","age","address","friends");  
person.name.should.equal("John");
person.age
  .should
      .be.number()
  .and.be.between(20,30);

person.address
  .should
    .be.string().and
    .startWith("\d").and
    .endWith(" st.")
  //or even
    .and.match(/^[0-9]{1,9}\s+[A-Z][a-z0-9 ]* st\.$/);

person.friends
  .should
    .be.array().and
    .be.between(3,5).and
    .containOnlyType(String);

这不是很棒吗?这是简单的英语!

你可以争论缩进的美学,在哪里放and,如果它们完全是必要的,但除此之外 - 任何人都可以读或写它: 一旦你采用<​​em>每个对象上存在的'should'属性,但不会破坏地图迭代 - 你可以继续链接任何关于你开始的价值的索赔。

它可以有更多漂亮的迭代工具,反射实用程序,可以使用与对象模型相关的测试函数进行扩充,依此类推,但是让我们来完成第一步:)

但为此,您需要系统中的每个对象都有一个名为should不可枚举的智能属性,其中包含 getter < / strong> function返回用Assertion构造的this对象作为测试值。

(你还没有看到任何东西 - 等着看它给出的美丽拒绝信息!Yummie !! 所以,是的 - 我很乐意牺牲选择一个属性“应该”...并且也会高兴地放弃知识分子 - 至少只要它是简单的英语)

所以,在评论中, bfavaretto 给了我们第一步 - 我们知道如何防止属性的枚举 - 伟大的&amp;谢谢!

现在,我们可以将其作为getter属性,其功能可以访问this吗?

当我完成后,我将把它放在麻省理工学院授权的公共仓库中,让我们所有人都玩得开心:)

帮助任何人?

3 个答案:

答案 0 :(得分:0)

你的例子实际上是90%正确 - 但是像动作一样定义它,而不是像javascript!

您仍然可以在AS3中定义原型,它们仍然可以像AS2中的原型一样工作。 AS3的唯一区别是编译器。 AVM2由于某种原因没有将原型转换为本机类(虽然我没有测试自定义类)。

原型技巧:将类作为对象进行投射。

例如:如果您创建:

  

Array.prototype.random = function():void {}

然后创建对象:

  

var myProtoArray:Array = new Array;

将会发生两件事:

  

myProtoArray.random()//错误 - 这将失败,AVM2没有将原型映射到数组

  

Object(myProtoArray).random()// WORKS

random()被强制转换为Object类,然后映射到Array - 我不知道为什么!

希望这会有所帮助,欢呼。

答案 1 :(得分:0)

我承认我并不十分熟悉Javascript的工作原理,但如果我正确地理解defineProperties目的,那么它不仅仅是属性的运行时指示,而且还是它所属的关联命名空间(或至少AS3认为是命名空间)。

类属性是预定义的&amp;只能通过自定义get()set()函数或动态修改。一旦编译,它们的命名空间就不能改变(据我所知),所以任何非私有属性都是隐式可枚举的,并且可以修改你是否已经编写了getter / setter(即:foo.a = value)。 According to Adobe...

  

您创建的属性是可枚举的,但内置属性是   一般不会列举。

也就是说,您可以使用describeType从类中获取完整的属性列表。可以通过这种方式收集相当多的信息,如果您想要移植Mozilla's recreated defineProperties示例,我怀疑应该满足您的需求。以下是仅打印属性值的示例。

function showProps(obj:*):void {
    var desc:XML= describeType(obj);

    // public vars
    for each (var n:XML in desc.variable){
        trace(n.@name + ": " + obj[n.@name]);
    }
    // getters
    for each (n in desc.accessor){
        try {
            trace(n.@name + ": " + obj[n.@name]);
        } catch (error:Error) {
            trace("Unable to read write-only property.");
        }
    }
}

我希望这会有所帮助,但我确定我并不完全理解你想要完成的事情。如果你能详细说明,那就不胜感激了。

答案 2 :(得分:0)

好的,伙计们,感谢所有帮助,22岁以上 我会给那些对原始问题感兴趣的人做一个总结,之后 - 我会告诉你我努力的结果。

挑战由两部分组成:

1 - 防止枚举增强(=运行时添加)属性

至于第一部分 - 感谢@bfavaretto,对问题级别发表了评论 - Object.setPropertyIsEnumerable - 这个技巧很棒。

2 - 使扩充属性运行一个可以访问this的getter函数,以便它可以在返回值的构造函数上使用它。

关于第二部分 - 基本上 - 我找不到一种方法来增加(=添加)一个属性getter到一个原型,让它通过继承树来操作它们的API。

无论如何,在这些限制范围内 - 结果如下:

https://github.com/osher/should.as

由于平台差异,不准确移植, 我还有一些方法可以赶上原来的should.js(比如HTTP测试方法) 但足够接近。 主要区别在于

var o:Object = 
    { name : "Radagast"
    , color: "Brown"
    }
o.should.have.properties("name","color")
    .and.have.property("name","Radagast");
o.name.should.not.equal("Palandoo");
o.color.should.equal("Brown");

你必须去

o.should().have.properties("name","color")
       and.have.property("name","Radagast");
o.name.should().not.equal("Palandoo");
o.color.should().equal("Brown");

(括号 - 没有可能的getter - 所以should属性是一个方法,你必须自己调用它)

现在,如果您遇到困难并需要智能感知的帮助,您必须这样做:

var should:tdd.Should = o.color.should();
should. <ctrl+space>

哪种有点刺痛,但是为了窥探知识分子 - 它有帮助

重要

还有一件事 - 你必须尽快强制执行We的静态构造函数, 例如,我在这里做:

[Suite]
[RunWith("org.flexunit.runners.Suite")]
public class my_awsome_test_suite
{
            //forces the static constructor of tdd.Should
    import tdd.Should;
    private static var s:Should = new Should(); 

    public var c1:testCase1;
    public var c2:testCase2;
    public var c3:testCase3;
    public var c4:testCase4;
    }

我可能会稍后添加一些propper README.md,并将更多令人敬畏的成员函数添加到tdd.Should

玩得开心