嵌套XMLHttpRequest中this指向异常及原理解析求助
核心问题1:错误地把函数执行结果赋值给了onload
看你代码里这一行:
reqObj.onload = buildProjects(reqObj, obj);
这里不是把buildProjects函数引用赋值给onload事件,而是直接执行了buildProjects函数,把它的返回值(因为函数没写return,实际是undefined)赋值给了onload。
这时候buildProjects是在全局作用域下直接调用的,非严格模式下this默认指向window,这就是为什么你拿到的是window而不是XHR对象。
而你单个请求时写的reqObj.onload = reqListener;是正确的——把函数引用给事件,当请求完成时,XHR对象会作为调用者去执行这个函数,此时this才会指向该XHR实例。
核心问题2:传递参数无效的原因
因为你直接执行了buildProjects,此时XHR请求还没发送完成,reqObj.responseText根本没有内容,所以你传递的reqObj虽然是正确的实例,但里面的响应数据是空的,自然达不到预期效果。
为什么单个请求时this正常?
JavaScript里this的指向完全由函数的调用方式决定:
- 当函数作为某个对象的方法被调用时(比如XHR对象触发onload时调用你的函数),
this指向这个对象。 - 当函数被直接调用(比如
fn()),非严格模式下this绑定到window,严格模式下是undefined。
你的单个请求场景中,reqListener是被XHR对象调用的,所以this指向XHR;而嵌套场景里,buildProjects是你手动直接调用的,所以this指向window。
为什么bind能解决问题?
bind()方法会创建一个新的绑定函数,这个函数被调用时,this会固定指向你传入的对象(比如reqObj.bind(reqObj)),同时还能预先传递你需要的参数(比如obj)。当XHR请求完成触发onload时,调用的是这个绑定后的函数,this就会指向你指定的XHR实例,参数也能正确传递。
给你改个正确的写法示例:
function reqListener() { var obj = JSON.parse(this.responseText) var reqObj = new XMLHttpRequest(); // 用bind绑定this为reqObj,同时预先传入obj参数 reqObj.onload = buildProjects.bind(reqObj, obj); reqObj.open("get", "post_box.html", true); reqObj.send(); } function buildProjects(data) { // 这里的this就是绑定的reqObj console.log("data is: " + data.title); console.log("State: " + this.readyState); console.log("Response is: " + this.responseText); }
内容的提问来源于stack exchange,提问作者DevJoe

