打包app 华为手机ajax失败引发的---重写jQuery的ajax方法
本文为18.11.8重新编写,原题目:extend合并对象
经测试,在华为Mate 10 的 EMUI 8.1 版本 8.1.0.336 下进行ajax调用出现异常(其他安卓手机调用正常);在调用后ajax会默认进入success并返回空数据。
所以首先尝试用原生的请求数据(配用appcan的插件),发现可以获取到数据~涉及到项目代码的改动。
那么为了解决这个问题:只好 重写ajax!!!!
一、前提知识(系统温习一下)
1. (function($){….})(jQuery)
第一个括号里边的function($){….}实际上就是一个匿名函数,它的形参是$,其实这里主要是为了不与其它的库冲突。
我们在调用函数的时候,通常都是函数名后边加上括号以及实参,但是由于操作符的优先级我们定义的匿名函数也需要用()括起来,所以就有了前面的(function($){....})。
第一个括号表示定义了一个匿名函数,然后(jQuery)表示为该函数传递的参数,整个结合起来意思就是,定义了一个匿名函数,然后又调用该函数,并传递实参jQuery,相当于——function fun($){…};fun(jQuery);
这种方法多用于存放开发的插件,执行其中的代码时,Dom对象并不一定加载完毕。于此相反的是$(function(){}),这种方法在使用时页面的Dom对象已经加载完毕了。事实上该方法的全写是:$(document).ready(function(){});
---------------------
2.$.fn.extend和$.extend
jQuery.fn.extend(object);//为jQuery的实例对象添加方法
jQuery.extend(object);//为jQuery类本身扩展,添加新的方法或覆盖原有的方法
$.fn.extend表示的是为原型对象扩展方法,使用此方式扩展的方法只能用对象去调用,example:
$.fn.extend({ test:function(){ alert("test"); } }); $("#id").test();
$.extend就可以直接用$在其他地方来调用此扩展方法了,example:
$.extend({ test:function(param){ alert(param); } }); $.test(1);//则直接弹出1
2.1 extend(result,item1,item2…..)
这里这个方法主要用来合并,将所有的参数项都合并result中,并返回result,但是这样就会破坏result的结构。
2.2 extend({},item1,item2,……)
用这个方法,可以将所得的结果全部合并在{}中,并返回,而且还不会破坏原有的项的结构。
示例:
Var item={name:”olive”,age:23};
Var item1={name:”Momo”,sex:”gril”};
Var result=$.extend({},item,item1);
结果:
Result={name:”Momo”,age:23,sex:”gril”};
2.3 extend(bool,{},item1,item2….)
Extend方法还有带bool型参数的重载。
bool型参数为true表示深拷贝,为false时表示浅拷贝。具体可以通过一下示例来说明:
示例:
var item={name:“olive”,age:23,address{provice:”河南”,city:”郑州”}}; var item1={sex:”girl”,address{city:”北京”}}; var result=$.extend(true,item,item1); var result1=$.extend(false,item,item1); 结果: Result={name:“olive”,age:23,sex:”gril”,address:{provice:”河南”,city:”北京”}}; Result1={name:“olive”,age:23,sex:”gril”,address:{ city:”北京”}};
说明:
以上结果说明,当参数为ture时,即为深拷贝,当子项item1中的子项有与item中的子项相同属性的值不一样时,item1中子项的值会将item子项中的值给覆盖,当子项item1的属性跟item中的属性不同时,会与item进行合并。
当参数为false时,子项item1中的子项中与item中的子项属性相同时,item1中子项的属性值会将item中的值给完全覆盖。
重点 :重写方法 用的是原生方式自己处理的,没有采用网上一搜一大把的完全一样的文章!
方式1:
$.extend($.ajax,{ ajax:function (opt) { .......this.options =$.extend({},this.defaults,opt); .......... } })
方式2:()
$.ajax = function (opt) {
this.defaults ={
'type': 'post',
'url': '',
'data':'',
'timeout':30000,
'async':true,
'contentType': "application/json",
'success':function () {},
'error':function () {}
}
//this.options =$.extend({},this.defaults,opt);//A
var thisoptions =$.extend({},this.defaults,opt);
console.log(this.options)
var self = this;
var xhr = new XMLHttpRequest();
xhr.open(thisoptions.type,thisoptions.url,thisoptions.async);
xhr.setRequestHeader('Content-Type',thisoptions.contentType);
xhr.send(thisoptions.data); //发送
xhr.onreadystatechange = function(event){
if(xhr.readyState == 4){
if (xhr.status >= 200 && xhr.status < 300) {
var message = '';
try {
message = JSON.parse(xhr.responseText);
} catch (err) {
self.options.error(err.message, xhr.status, xhr,2);
}
if (message) {
thisoptions.success(message, xhr.status, xhr,3);
}
} else {
self.options.error(xhr.statusText, xhr.status, xhr,4);
}
}
}
if(thisoptions.timeout > 0){
xhr.ontimeout = function () {
self.options.error(xhr.statusText, xhr.status, xhr);
};
}
}
至此:就可以使用了!
发现的问题:
1.请求头的问题。这个封装方式 需要单独的设置请求头!由于项目中 存在多个服务,而且这些服务是不的人不同的时间段写的。一个请求头高端华为手机竟然没法同时满足,
2.发现的bug:$.extend({})问题
这里最初仅仅是$.extend({})形式。项目中竟然出现了请求2次数据的问题!也就是说:重写的ajax没有覆盖 jQuery的,依然会执行jQuery的ajax!
然后升级一下:$.extend(true,$.ajax,{}),本以为这样会覆盖jQuery了。第二天发现还是不行!------------由于多个项目中都用了$.ajax形式,那么想到过 把jQuery的ajax换个名字,换个名字是做到清除jQuery的ajax的影响了~~但是改了jQuery,不合时宜!!
最终:直接 $.ajax = function(){}方式!
3.重大问题:
方式1 中的 this.options =$.extend({},this.defaults,opt) 到了方式2 中,变了~~~ 就这么一句代码 给我造成了大困扰!尝试了一天多的解决方式!
方式一中的 写法,有个有趣的现象:如果是同时执行多个ajax函数!每个都会返回正常值,但是:返回的正常值会按最后一个函数的回调方式 处理!!!
//三个ajax函数 fun1() fun2() fun3() //三个都会返回自己的值。但是 都会按照fun3的处理方式处理返回值!!! //单独一个函数还好 //想过 依次调用回调 执行,但这样依旧没有从根本上解决问题!!!其实还是封装写法某个地方出的问题---- this.options =$.extend({},this.defaults,opt) 引起的
扩展:原生JavaScript实现ajax
function ajax(options) { options = options || {}; options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; var params = (options.data); //创建xhr对象 - 非IE6 if (window.XMLHttpRequest) { var xhr = new XMLHttpRequest(); } else { //IE6及其以下版本浏览器 var xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //GET POST 两种请求方式 if (options.type == "GET") { xhr.open("GET", options.url + "?" + params, true); xhr.send(null); } else if (options.type == "POST") { xhr.open("POST", options.url, true); //设置表单提交时的内容类型 xhr.setRequestHeader("Content-Type", "application/json"); xhr.send(params); } //接收 xhr.onreadystatechange = function () { if (xhr.readyState == 4) { var status = xhr.status; if (status >= 200 && status < 300) { options.success && options.success(JSON.parse(xhr.responseText)); } else { options.fail && options.fail(status); } } } }
扩展:zepto.js的ajax实现
appcan封装的ajax完全就是zepto.js
zepto.js 源码带注释 说明连接 http://www.runoob.com/w3cnote/zepto-js-source-analysis.html
扩展:原生JavaScript实现extend
var obj1 = {'a': 'obj2','b':'2'}; var obj2 = {name: 'obj3'}; function extend() { var length = arguments.length; var target = arguments[0] || {}; if (typeof target!="object" && typeof target != "function") { target = {}; } if (length == 1) { target = this; i--; } for (var i = 1; i < length; i++) { var source = arguments[i]; for (var key in source) { // 使用for in会遍历数组所有的可枚举属性,包括原型。 if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; } console.log(extend(obj1,obj2));
原文内容:
需求:设有对象 o1 ,o2,需要得到对象 o3
方法1:使用JQuery的extend方法
**方法定义**:jQuery.extend([deep], target, object1, [objectN])
> 用一个或多个其他对象来扩展一个对象,返回被扩展的对象。
> 如果不指定target,则给jQuery命名空间本身进行扩展。这有助于插件作者为jQuery增加新方法。 如果第一个参数设置为true,则jQuery返回一个深层次的副本,递归地复制找到的任何对象(递归合并)。否则的话,副本会与原对象共享结构。 未定义的属性将不会被复制,然而从对象的原型继承的属性将会被复制。
o3 = $.extend(o1, o2) // 合并 o1 和 o2, 将结果返回给 o3. 注意: 此时,o1 == o3! 即 o1 被修改 // 或 o3 = $.extend({}, o1, o2) // 合并 o1 和 o2, 将结果返回给 o3. 注意: 此时,o1 != o3! 即 o1 没有被修改
方法2:用 Object.assign();
var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
JavaScript中Math.abs()方法的使用
Math.abs( x ) ;
- 返回一个数字的绝对值
333