فئة JavaScript تدعو XmlHttprequest داخليًا ، ثم التعامل مع onReadyStateChange
-
26-09-2019 - |
سؤال
هذا الشيء يعمل تقريبا:
function myClass(url) {
this.source = url;
this.rq = null;
this.someOtherProperty = "hello";
// open connection to the ajax server
this.start = function() {
if (window.XMLHttpRequest) {
this.rq = new XMLHttpRequest();
if (this.rq.overrideMimeType)
this.rq.overrideMimeType("text/xml");
} else
this.rq = new ActiveXObject("Microsoft.XMLHTTP");
try {
this.rq.onreadystatechange = connectionEvent;
this.rq.open("GET", this.source, true);
this.rq.send(null);
this.state = 1;
} catch (err) {
// some error handler here
}
}
function connectionEvent() {
alert("i'm here");
alert("this doesnt work: " + this.someOtherProperty);
}
} // صفي
لذلك ليس أكثر من مجرد كائن XMLHTTPrequest كعضو في صفي ، بدلاً من تعريفه عالميًا ، واستدعاءه بالطريقة التقليدية. ومع ذلك ، داخل وظيفة رد الاتصال الخاصة بي ، يتم فقد معنى "هذا" ، على الرغم من أن الوظيفة نفسها يتم تحديدها داخل MyClass. لقد تأكدت أيضًا من أن الكائن الذي أقوم بتثبيته من MyClass قد أبقى على قيد الحياة لفترة كافية (أعلن عالمي في البرنامج النصي).
في جميع الأمثلة على استخدام فصول JavaScript التي رأيتها ، كان "هذا" لا يزال متاحًا داخل الوظائف الداخلية. بالنسبة لي ، ليس الأمر كذلك ، حتى لو أخذت وظيفتي في الخارج وجعلها myclass.prototype.connectionevent. ما الخطأ الذي افعله؟ شكرا.
المحلول
السبب في عدم عمله هو أنه في JavaScript ، this
يتم تعريفه بالكامل من خلال كيفية الوظيفة اتصل, ، ليس حيث يتم تعريفه. هذا يختلف عن بعض اللغات الأخرى.
امتلاك this
يعني ما تتوقعه ، يجب عليك التأكد من ذلك بشكل صريح عن طريق "ربطه":
this.start = function() {
var self = this; // Set up something that survives into the closure
/* ...lots of stuff omitted... */
this.rq.onreadystatechange = function() {
// Call `connectionEvent`, setting `self` as `this` within the call
connnectionEvent.call(self);
};
هناك المزيد من المعلومات حول this
الإدارة في منشور المدونة هذا, ، ولكن في الأساس: عندما يتم استدعاء وظيفة دون أي جهد معين تم تعيينه this
, this
ضمن الوظيفة سيكون دائمًا الكائن العالمي (window
, ، على المتصفحات). هناك طريقتان لتعيين this
عند إجراء مكالمة:
- استخدام
Function#call
(أوFunction#apply
) كما فعلت أعلاه ، تمرير مرجع الكائن لاستخدامهthis
كمعلمة الأولى. الذي يدعو الوظيفة ويحددthis
إلى كل ما مررت به. الفرق بين#call
و#apply
هي الطريقة التي تقدم بها المزيد من الحجج لتمرير الوظيفة. مع#call
أنت تزودهم كحجيلات أخرى إلى#call
استدعاء (على سبيل المثالfunc.call(thisArg, arg0, arg1, arg2)
) ، مع مع#apply
يمكنك تزويدهم كصفيف في الحجة الثانية (func.apply(thisArg, [arg0, arg1, arg2])
). - باستخدام تدوين منقط: إذا كان لديك كائن يحتوي على خاصية مع وظيفة مخصصة لها (مثل الخاص بك
start
خاصية) ، ودعاها باستخدام مثيل الكائن ، ونقطة ، واسم الخاصية (this.start()
أوfoo.start()
, ، وما إلى ذلك) سوف يتصل بالوظيفة وتعيينthis
إلى مثيل الكائن داخل المكالمة. لذا فإن التدوين المنقط يفعلان مميزة تماما الأشياء: تبحث عن العقار ويجد وظيفة كقيمة لها ، وتدعو الوظيفة من هذا القبيلthis
تم تعيينه على الكائن أثناء المكالمة. حرفيا مثل:var f = obj.func; f.call(obj)
.
خارج الموضوع قليلاً ، ولكن: باستثناء سبب وجيه حقًا ، لن أعيد اختراع هذه العجلة. هناك الكثير من المكتبات لمكالمات XHR ببساطة. jQuery, النموذج المبدئي, إنهاء, ، وكل ما يقرب من الباقي.