JavaScript参数值变为'传递给构造函数时未定义

时间:2017-02-22 16:32:29

标签: javascript ecmascript-6

我正在创建一个JavaScript组件,我正在创建基于jQuery结果的实例,但是,我传递给构造函数的DOM元素,虽然在我在调用代码中逐步执行循环时填充,但是在传递给构造

这是我的班级和建设者......

export default class DeleteButton {

    /**
     * Creates an instance of DeleteButton.
     * 
     * @param {object} element The DOM element to make into a delete button.
     * 
     * @memberOf DeleteButton
     */
    constructor(element) {        
        this.id = element.getAttribute("data-id");
        if (!this.id) throw new Error("The 'data-id' attribute is required.");

        this.deleteUri = element.getAttribute("data-delete-uri");
        if (!this.deleteUri) throw new Error("The 'data-delete-uri' attribute is required.");

        $(element).click(this.confirmRemove);
    }

    confirmRemove() { // does something }
}

这里是调用代码(这是一个组件管理器,它根据URL / DOM状态等处理组件的加载时间)...

export default class JsComponentManager {

    constructor(onLoader) {
        this._loader = onLoader;
        this.select = {
            deleteButtons: () => $(".js-delete-button")
        }
        this.result = 0;
    }

    bindComponents() {
        const paths = new PathManager();
        let $deleteButtons = this.select.deleteButtons()
        if ($deleteButtons.length > 0) {
            this._loader.add(this.renderDeleteButtons, $deleteButtons);
        }
    }

    renderDeleteButtons($elements) {
        $elements.each(() => {
            document.DeleteButtons = document.DeleteButtons || [];
            document.DeleteButtons.push(new DeleteButton(this));
        });
    }
}

这使用以下加载器函数来确保加载项目......

/**
 * Adds an event to the onload queue.
 * 
 * @param {function} func The function to add to the queue.
 * @param {any} param1 The first (optional) parameter to the function.
 * @param {any} param2 The second (optional) parameter to the function.
 */
var AddLoadEvent = function (func, param1, param2) {
    var oldonload = window.onload;
    if (typeof window.onload !== "function") {
        window.onload = () => { func(param1, param2); };
    } else {
        window.onload = () => {
            if (oldonload) { oldonload(); }
            func(param1, param2);
        };
    }
};

module.exports = {
    add: AddLoadEvent
};

onload管理代码似乎运行良好,并且逐步完成代码执行完全符合预期,直到document.DeleteButtons.push(new DeleteButton(this)); - '这个'这是DOM元素,正如我所料,但只要调试器进入控制器,值就是未定义的。

这是一种奇怪的范围内的痛苦我已经走进了吗?

2 个答案:

答案 0 :(得分:2)

renderDeleteButtons($elements) {
    $elements.each(() => {
        document.DeleteButtons = document.DeleteButtons || [];
        document.DeleteButtons.push(new DeleteButton(this));
    });
}

没有做你认为的事情。 jQuery依赖于能够设置回调函数的this值。但箭头功能没有自己的this,因此jQuery无法设置this值。

在箭头函数this中,将引用thisrenderDeleteButtons引用的任何内容,这可能是JsComponentManager的实例。

如果将函数传递给另一个函数并且该函数必须设置this值,则不能使用箭头函数。请改用函数表达式:

renderDeleteButtons($elements) {
    $elements.each(function() {
        document.DeleteButtons = document.DeleteButtons || [];
        document.DeleteButtons.push(new DeleteButton(this));
    });
}

另请参阅:Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?

这可能有助于证明箭头函数和函数声明/表达式之间的区别:



// our library:
function each(values, callback) {
  for (var i = 0; i < values.length; i++) {
    // we use `.call` to explicitly set the value of `this` inside `callback`
    callback.call(values[i]);
  }
}


// Function declaration/expression
var obj = {
  someMethod() {
    "use strict";
    each([1,2,3], function() {
      console.log('function declaration:', this);
    });
  },
};

// Because we use a function expression, `each` is able to set the value of `this`
// so this will log the values 1, 2, 3
obj.someMethod();

// Arrow function
obj = {
  someMethod() {
    each([1,2,3], () => {
      "use strict";
      console.log('arrow function:', this);
    });
  },
};

// `this` is resolved lexically; whatever `each` sets is ignored
// this will log the value of `obj` (the value of `this` inside `someMethod`)
obj.someMethod();
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我现在通过放弃jQuery.each来解决这个问题(这似乎有严重的范围问题,将元素从数组传递到其他任何东西,因为它混淆了这个&#39;这个&#39;) 。我通过使用JS forEach调用解决了这个问题,如下所示。发现jQuery的makeArray方法是关键。这与我最初开始时的情况类似,但是我正在敲打forEach而不是在jQuery对象上工作......

renderDeleteButtons($elements) {
    $.makeArray($elements).forEach((el) => {
        document.DeleteButtons = document.DeleteButtons || [];
        document.DeleteButtons.push(new DeleteButton(el));
    });
}

通过使用&#39;这种奇怪的东西,它也不会伤害我的敏感度。 (对于费利克斯)

请参阅Felix关于词汇范围的额外信息&#39; this&#39;在Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?