2017-02-22 3 views
0

Я создаю компонент JavaScript, который я создаю экземпляры на основе результатов jQuery, однако элемент DOM, который я передаю в конструктор, хотя и заполняется, когда я перехожу через цикл в вызывающем коде, не определено при передаче конструктору.Значение параметра JavaScript становится «undefined при передаче конструктору

Вот мой класс и конструктор ...

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 
}; 

Код управления нагрузкой, похоже, работает нормально, и, шаг за шагом, выполнение кода полностью ожидалось до document.DeleteButtons.push(new DeleteButton(this));. «Это» здесь элемент DOM, как и следовало ожидать, но как только отладчик переходит в контроллер, значение не определено.

Является ли это какой-то странной болезненной болью, в которую я вошел?

+0

* "но как только отладка er в контроллер, значение не определено ». * Вы говорите, что' element' является 'undefined' в конструкторе' DeleteButton'? Не уверен, что я понимаю, в чем проблема. Однако то, что вы передаете 'DeleteButton', является экземпляром' JsComponentManager', а не элементом. См. Http://stackoverflow.com/q/34361379/218196. –

+0

Нет - я не (и я знаю, что это странно), «это» в jQuery, каждый из них является самим элементом. См. Мой ответ ниже для более подробной информации. По сути, каждый jQuery представляет собой полный ужас, который, похоже, не может передать элемент из себя из-за ограниченного объема. –

+0

Пожалуйста, взгляните на вопрос, с которым я связан. –

ответ

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

не делать то, что вы думаете, что он делает. jQuery полагается на возможность установить значение функции обратного вызова this. Но функции стрелки не имеют собственных this, поэтому jQuery не может установить значение this.

Внутри функции this стрелки будет ссылаться на то, что относится к this в renderDeleteButtons, который, вероятно, является экземпляром 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();

+0

Это отличный ответ! Спасибо Феликс! –

0

У меня теперь есть эта работа, отказавшись от jQuery.each (у которого, похоже, есть серьезные проблемы с определением области пропуска, передающие элемент из массива на что-нибудь еще из-за того, как он смешивается с «этим»). Я решил это, используя вместо этого вызов JS forEach следующим образом. Обнаружение метода makeArray jQuery было ключевым. Это похоже на то, что я начал с первоначально но стучал головой о Foreach не работает на объекте JQuery ...

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

Он также не повредит мои чувства, делая странные вещи с «это» (для Felix) дополнительной информации

знакомства Феликса по лексической области видимости с «это» в Arrow function vs function declaration/expressions: Are they equivalent/exchangeable?

Смежные вопросы