From closures to prototypes, part 2 (转)

本文介绍如何将使用Atlas和闭包模式定义的JavaScript类转换为原型模式类,并列出转换过程中的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In part 1 of this post, I exposed the differences between the closure and the prototype patterns to define JavaScript classes. In this post, I'll show the shortest path to convert an existing class built using Atlas and closures to a prototype-based class. I'll also show a few caveats that you need to be aware of.

Here's an example of a class built using the July CTP of Atlas:

Custom.Color = function(r, g, b) {
Custom.Color.initializeBase(this);
var _r = r || 0;
var _g = g || 0;
var _b = b || 0;
this.get_red function() {
return _r;
}
this.set_red  function(value) {
_r = value;
}
this.get_green  function() {
return _g;
}
this.set_green  function(value) {
_g = value;
}
this.get_blue  function() {
return _b;
}
this.set_blue  function(value) {
_b = value;
}
this.toString  function() {
return Custom.Color.callBaseMethod(this, toString) +
"(" + _r + "," + _g + "," + _b + ")";
}
Custom.Color.registerBaseMethod(this, "toString");
}
Custom.Color.registerClass("Custom.Color", Sys.Component);

The first thing you need to do is insert the following right after the private variable initialization, as this is all that's needed now in the constructor:

}
Custom.Color.prototype = {

Then you need to replace the variable initializations in the constructor with instance variable initialization:

  this._r = r || 0;
this._g = g || 0;
this._b = b || 0;

The next step is of course to replace all occurrences of _r, _g and _b with this._r, this._g and this._b throughout the rest of the code.

Note the convention that private members (fields and methods) are prefixed with an underscore. This convention will be adopted by Visual Studio Orcas in IntelliSense.

For each method and property accessor, you need to remove the "this." before the name and replace the " = " with ": ". Also add a comma after the closing brace of each method but the last one. Finally, remove any registerBaseMethod you may have (in prototype-based classes, everything is virtual).

That's it, your class is now built using prototypes:

Custom.Color = function(r, g, b) {
Custom.Color.initializeBase(this);
._r = r || 0;
._g = g || 0;
._b = b || 0;

  get_red function() {
return ._r;
}
set_red function(value) {
._r = value;
}
get_green function() {
return ._g;
}
set_green function(value) {
._g = value;
}
get_blue function() {
return ._b;
}
set_blue function(value) {
._b = value;
}
toString function() {
return Custom.Color.callBaseMethod(this, toString) +
"(" + ._r + "," + ._g + "," + ._b + ")";
}
}
Custom.Color.registerClass("Custom.Color", Sys.component);

I've highlighted where the code differs in both samples for easy reference.

So that was easy. Now let's enumerate a few do's and don't's...

  • Do transform private constructor variables into underscore-prefixed instance fields.
    Foo.Bar = function() {
        var _baz = "";
        }
    becomes
    Foo.Bar = function() {
        this._baz: ""
        }
  • Do move all methods and property accessors from the constructor to the prototype.
  • Do update all references to fields and methods to be dereferenced through the this pointer.
    _member
    becomes
    this._member
  • Do separate prototype members with commas, but don't leave a comma after the last one (JSON syntax doesn't allow it).
  • Don't use the instanceof operator with Atlas classes. Do use 
    MyNamespace.MyType.isInstanceOfType(myInstance)
    instead of 
    myInstance instanceof MyNamespace.MyType
  • Do continue to set initial values of fields from the constructor.
  • Don't move field initializations that depend on the this pointer to prototype (but do make them fields)
    Foo.Bar = function() {
        var _delegate = Function.createDelegate(this, this._handler);
        }
    becomes
    Foo.Bar = function() {
        this._delegate = Function.createDelegate(this, this._handler);
        }
  • Don't register base methods: with the prototype pattern, all methods are virtual. The registerBaseMethod will not be available in Atlas starting with Beta 1, which makes it impossible for closure-based classes to be base Atlas classes.
  • Do move private functions to the prototype (prefixing the name with underscore) unless they have a compelling use of the closure pattern (for security for example), which is quite rare.
    Foo.Bar = function() {
        function privateMethod() {
        //...
        }
        }
    becomes
    Foo.Bar = function() {}
        Foo.Bar.prototype = {
        _privateMethod: function() {
        //...
        }
        }

In the next posts, I'll get into other specific changes that we're making in Beta 1.

转载于:https://www.cnblogs.com/fengmk2/articles/532829.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值