2017-02-22 1 views
0

Ich erstelle eine JavaScript-Komponente, die ich Instanzen von jQuery Ergebnisse erstellen, aber das DOM-Element, das ich in den Konstruktor übergeben, obwohl ausgefüllt, wenn ich durch die Schleife gehe im aufrufenden Code ist undefiniert, wenn es an den Konstruktor übergeben wird.JavaScript-Parameterwert 'wird' undefiniert, wenn an Konstruktor übergeben

Hier ist meine Klasse und Konstruktor ...

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

und hier ist der aufrufende Code (Dies ist eine Komponente-Manager, wenn Griffe Komponenten zu laden, basierend auf URLs/DOM Zustand etc) ...

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

Dies verwendet die Funktion folgende Lader, um sicherzustellen, dass Gegenstände geladen werden ...

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

Der Onload-Management-Code scheint gut zu laufen, und Code-Execution ist vollständig, wie erwartet, bis document.DeleteButtons.push(new DeleteButton(this)); - 'dies' hier ist das DOM-Element, wie ich erwarten würde, aber sobald der Debugger in den Controller tritt der Wert ist nicht definiert.

Ist das ein seltsamer Scoping-Schmerz, auf den ich gestoßen bin?

+0

* "aber sobald die debugg Wenn man in den Controller tritt, ist der Wert undefiniert. "* Willst du sagen, dass' element' im 'DeleteButton' Konstruktor' undefiniert' ist? Nicht sicher, ich folge, was das Problem ist. Was Sie jedoch an DeleteButton übergeben, ist eine Instanz von 'JsComponentManager', kein Element. Siehe http://stackoverflow.com/q/34361379/218196. –

+0

Nein - ich bin nicht (und ich weiß, es ist seltsam) "das" in jQuery ist jeder das Element selbst. Siehe meine Antwort unten für weitere Details. Im Wesentlichen ist jeder eine totale Scheußlichkeit, die aufgrund begrenzter Reichweite nicht in der Lage ist, das Element aus sich selbst heraus zu geben. –

+0

Bitte werfen Sie einen Blick auf die Frage, die ich verlinkt habe. –

Antwort

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

nicht tut, was Sie denken, es tut. jQuery benötigt den Wert this der Callback-Funktion. Aber Pfeilfunktionen haben keine eigenen this, so kann jQuery den this Wert nicht einstellen.

Innerhalb der Pfeilfunktion this wird, was auch immer beziehen this in renderDeleteButtons bezieht, die wahrscheinlich eine Instanz von JsComponentManager ist. Wenn Sie eine Funktion an eine andere Funktion übergeben und diese Funktion den Wert this setzen muss, können Sie keine Pfeilfunktion verwenden.Verwenden Sie einen Funktionsausdruck statt:

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

Siehe auch:

// 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();
: Arrow function vs function declaration/expressions: Are they equivalent/exchangeable?


Vielleicht den Unterschied zwischen einem Pfeil Funktion und eine Funktion Erklärung/Ausdruck zu zeigen, hilft

+0

Dies ist eine großartige Antwort! Danke Felix! –

0

Ich habe jetzt funktioniert dies durch Aufgeben von jQuery.each (die scheint schwerwiegende Probleme mit dem Scoping das Element aus dem Array an etwas anderes aufgrund der Art, wie es mit 'this') übergeben. Ich löste das, indem ich einen JS forEach Anruf wie folgt benutze. Das Auffinden der jQuery-Methode makeArray war der Schlüssel. Dies ist ähnlich zu dem, was ich mit ursprünglich begonnen hatte, wurde aber schlug meinen Kopf gegen forEach nicht auf einem jQuery-Objekt arbeiten ...

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

Es ist auch nicht meine Gefühle verletzt durch seltsame Dinge mit ‚this‘ zu tun (für Felix)

See Felix zusätzliche Informationen über lexikalische Bindung mit 'this' auf Arrow function vs function declaration/expressions: Are they equivalent/exchangeable?

Verwandte Themen