Dojo自定义组件的属性始终为默认值

时间:2014-10-08 10:32:08

标签: dojo

我编写了一个自定义组件来创建一个html按钮。 自定义组件定义如下

dojo.provide("ovn.form.OvnButton") ;

require([ "dojo/_base/declare",
       "dojo/dom-construct",
       "dojo/parser",
       "dojo/ready",
       "dijit/_WidgetBase"],
       function (declare, domConstruct, parser, ready, _WidgetBase){

       return declare ("ovn.form.OvnButton",[_WidgetBase],{

            label: "unknown",            
            constructor : function(args){
                this.id = args.id;
                args.props.forEach(function(prop) {
                    if(prop.name == 'label'){
                        this.label = prop.value;
                        alert("found label " + this.label);
                    }                         
                });
                alert("from constructor " + this.label);
            },
            postMixInProperties : function(){
            },
            buildRendering : function(){

                alert("from renderer label is " + this.label);
                this.domNode = domConstruct.create("button", { innerHTML: this.label }); //domConstruct.toDom('<button>' + this.label + '</button>');
            },
            _getLabelAttr: function(){
                return this.label;
            },
            _setLabelAttr : function(label){
                alert("from set input is " + label)
                this.label = label;
            },             
            postCreate : function(){
                alert("Post create label is " + this.label);
            },
            startUP : function(){
            }
        });

});

这就是我实例化组件的方式

var button = new ovn.form.OvnButton({
                          id:'run',
                          props:[{"name":"label","value":"Run"},{"name":"class","value":"btn"}]
                      });

在自定义组件的构造函数中,我遍历传递的数组并分配给名为&#39; label&#39;的实例变量。令我惊讶的是,当我们在buildRendering函数中打印实例变量时,它仍然打印默认值而不是指定的值。

有人可以解释为什么会这样。

供参考: 我在控制台上收到以下消息序列 1.found标签运行 2.来自构造函数未知 3.来自渲染器标签未知 4.来自设置输入未知 5.帖子创建标签未知

1 个答案:

答案 0 :(得分:0)

这是因为在小forEach函数中,this实际指向与OvnButton对象完全不同的东西。

Javascript&#39; this关键字在这方面很奇怪(实际上它与Dojo没有任何关系)。您可以在此处详细了解其工作原理:http://howtonode.org/what-is-this。这是一个非常基本的Javascript概念,与其他语言不同,因此值得您花些时间熟悉它。

但是有很多不同的方法可以快速解决它,所以这里有几个!

使用常规for循环而不是forEach和callback

最简单的可能是使用常规for循环而不是forEach进行回调。

....
// args.props.forEach(function(prop) {
for(var i = 0, l = args.props.length; i < l; i++) {
    var prop = args.props[i];    
    if(prop.name == 'label'){
        this.label = prop.value;
        alert("found label " + this.label);
    }                         
}//); <-- no longer need the closing parenthesis

这里要说的是Javascript的this魔法只发生在函数调用中,所以在这种情况下,当我们只使用for循环时,this继续指向正确的东西

...或者使用forEach的第二个thisArg参数

但也许你真的想用forEach。它实际上有第二个参数,通常称为thisArg。它告诉forEach确保this指向您在回调函数中选择的内容。所以你会做这样的事情:

....
args.props.forEach(function(prop) {
            if(prop.name == 'label'){
                this.label = prop.value;
                alert("found label " + this.label);
            }                         
        }, this); // <--- notice we give forEach two arguments now,
                  //      the callback function _and_ a "thisArg" value

我并不完全确定上述内容适用于所有浏览器,所以这是解决问题的另一种方法:

...或使用临时的&#34; self&#34;变量

我们将临时变量设为this。人们经常称这样的变量self,但你可以任意命名。这很重要:它只是Javascript在回调函数中处理不同的this关键字:

....
var self = this; //<--- we basically give `this` an alternative
                 //     name to use inside the callback.
args.props.forEach(function(prop) {
            if(prop.name == 'label'){
                self.label = prop.value; //<--- replaced `this` with `self`
                alert("found label " + self.label); //<--- here as well
            }                         
        });

...或者使用来自dojo / _base / lang

的hitch()

有些人不喜欢self解决方案,可能是因为他们喜欢始终使用this来引用拥有的对象。因此,许多框架都有一个&#34; bind&#34;函数,确保在特定范围内始终调用函数。在dojo的情况下,该函数被称为hitch。以下是如何使用它:

require([....., "dojo/_base/lang"], function(....., DojoLang) {
    ....
    args.props.forEach(DojoLang.hitch(this, function(prop) {
            if(prop.name == 'label'){
                this.label = prop.value;
                alert("found label " + this.label);
            }                         
        }));

...或使用Javascript自己的bind()

Dojo和几乎所有其他框架都有一个hitch()函数。因为它是Javascript中常用的概念,新的Javascript标准实际上引入了它自己的变体Function.prototype.bind()。您可以像这样使用它:

....
args.props.forEach(function(prop) {
    if(prop.name == 'label'){
        this.label = prop.value;
        alert("found label " + this.label);
    }                         
}.bind(this));

对于一个非常小的事情,这是一个非常长的答案,我希望它有一定意义!