javascript综合 二(闭包,堆内存和栈内存,promise,宏任务和微任务,Set和Map,typeOf和instanceOf,ajax,Boolean()和Number(),判断数组的方法)

闭包

在这里插入图片描述

闭包(closure)指有权访问另一个函数作用域中变量的函数
一个作用域可以访问另一个函数的局部变量
闭包的主要作用:延伸了变量的作用范围

//fun方法访问了fn中的变量,所以fn是闭包函数
function fn() {
    var num = 10;
    fun();

    function fun() {
        console.log(num);//打印10
    }
}
fn();

因为函数内部可以访问函数外部的变量,但是函数外部不可以访问函数内部的变量,即fun可以访问fn的所有变量但是fn不能访问fun的变量。当我们将fun作为返回值后,fn外部的函数就可以访问fn内的变量了
闭包的案例1
循环点击事件-用闭包的方式得到当前小li的索引号

//一般的方法
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
	//当点击后执行该函数 i已经为4了 只是不能进入到for循环中
	//for循环相当于一个闭包 点击事件内的i引用的是for循环中的变量 当i为4时 打印的结果也为4
	// lis[i].onclick = function() {
	//     console.log(i);//打印结果为都是4
	// }
	
	//正确方法
    lis[i].index = i;
    lis[i].onclick = function() {
    	//注意这里是this!!!!
        console.log(this.index);
    }
}

//闭包的方法
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
    
    //立即执行函数会形成一个单独的作用域,我们可以封装一些临时变量或者局部变量,避免污染全局变量
    //所以这里的for循环会创建4个立即执行函数,给每个li创建一个独立的作用域
    //相当于一个闭包
    //记住这个写法!
    (function(i){
        lis[i].onclick=function(){
            console.log(i);
        }
    })(i);
}

闭包的案例2
在一定时间之后打印所有li元素的内容

//3秒后打印所有li元素的内容
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
    //这里跟上面同理
    //因为settimeout里的回调函数也是异步的 要等主线程的任务执行完了才执行settimeout
    //所以不能直接在for循环里面写settimeout函数
    (function(i) {
        setTimeout(() => {
            console.log(lis[i].innerText);
        }, 3000);
    })(i);
}

例题1

//例题1
var name = "The window";
var object = {
    name: "my object",
    getNameFunc: function() {
        return function() {
            return this.name;
        }
    }
}
console.log(object.getNameFunc()());//打印 the window
//可以一步一步分解成
// var f = object.getNameFunc();
// 即f = function() {
//     return this.name;
// }
// object.getNameFunc()() 则为f(), 即
//f()=(function(){
//     return this.name;
// })();
//这就是执行了一个匿名函数,匿名函数的调用者是window
//所以这里面的this指的是window
//所以打印出来是the window
//这里没有闭包

例题2

//例题2
var name = "The window";
var object = {
    name: "my object",
    getNameFunc: function() {
        var that = this;
        return function() {
            return that.name;
        }
    }
}
console.log(object.getNameFunc()());//打印my object
//可以一步一步分解成
// var f = object.getNameFunc();
// 即f = function() {
//     return that.name;
// }
// object.getNameFunc()() 则为f(), 即
//f()=(function(){
//     return that.name;
// })();
//这里的that是getnamefunc方法里面的this,getnamefunc的调用者是object
//所以这里面的this指的是object
//所以打印出来是my object
//这里使用了闭包 getnamefunc就是一个闭包函数

闭包的问题:
由于闭包回携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过度使用闭包可能会导致内存占用过多。
作用域链的配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值

js中的栈内存和堆内存

栈内存主要存储各种基本类型的变量,包括boolean,number,string,undefined,null, * * 以及对象变量的指针 。比如var a=new A()中,变量a就是存储在栈中,而new出来的对象存储在堆上,对应地址是指针a存的内容
堆内存主要存储像对象Object这种变量类型的存储
在这里插入图片描述

promise

解决回调地狱的问题
假如有好几个函数依赖调用,即b依赖a,c依赖b,d依赖c。因为ajax的依赖关系会导致一个很深的回调嵌套,这就是回调地狱

promise是一个对象,用来传递异步操作的消息。
promise对象代表一个异步操作,有三种状态:
Pending(进行中)
Resolved(已完成 也叫做fulfilled)
Rejected(已失败)
只有异步操作的结果,可以决定当前是哪一种状态。一旦状态设定了就不能改变。
promise中的回调函数(即.then中的内容)是在微任务中的,其他的是在主线程中。
promise必须有一个then方法,then方法必须返回一个promise
基本语法:

//pending 准备阶段
//resolved 成功状态
//rejected 失败状态

new Promise((resolve, reject) => {
    //resolve和reject中的参数会传递到then中
    resolve("成功状态");
    //reject("拒绝状态");
}).then(
    //成功
    value => {
        console.log(value + ":成功后的业务处理1");
    },
    //失败
    reason => {
        console.log(reason + ":失败后的业务处理1");
    }
)


//Promise.then返回的也是一个Promise对象
var p1 = new Promise((resolve, reject) => {
    //resolve和reject中的参数会传递到then中
    resolve("成功状态");
    //reject("拒绝状态");
})
var p2 = p1.then(
    //成功
    value => {
        console.log(value + ":成功后的业务处理1");
    },
    //失败
    reason => {
        console.log(reason + ":失败后的业务处理1");
    }
)
console.log(p2);//p2也是一个promise

简单实现一个promise-原生js实现promise的封装

//简单实现一个promise
function myPromise(constructor) {
    this.status = "pending";//定义状态改变前的初始状态
    this.value = undefined;//定义状态为resolved的时候的状态
    this.reason = undefined;//定义状态为rejected的时候的状态

    function resolve(value) {
    //两个==="pending",保证了状态的改变是不可逆的
        if (this.status === "pending") {
            this.value = value;
            this.status = "resolved";
        }
    }

    function reject(reason) {
    //两个==="pending",保证了状态的改变是不可逆的
        if (this.status == "pending") {
            this.reason = reason;
            this.status = "rejected";
        }
    }
    //捕获构造异常
    try {
        constructor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

//在myPromise的原型上定义链式调用的then方法
myPromise.prototype.then = function(onFullfilled, onRejected) {
    let self = this;
    switch (self.status) {
        case "resolved":
            onFullfilled(self.value);
            break;
        case "rejected":
            onRejected(self.reason);
            break;
        default:
    }
}

//为什么这里的status是undefined呢 
//用已有的promise对象打印出status也是undefined
var p = new Promise(function(resolve, reject) {
    resolve("成功2222");
})
console.log(p.status); //undefined
p.then(function(value, reason) {
    console.log(value);//成功2222
    console.log(reason);//undefined
})

then返回值的处理
如果then里面有返回值,则后一个then是对这个返回值进行处理,即接受到的参数就是这个返回值,默认是成功状态。
如果then里面没有另加返回值,则后一个then是对前一个then返回的promise对象进行处理。例如:

new Promise(resolve => {
    resolve("resolve");
}).then(value => {
    return "then1";
}, reason => {
    return "reason1"
}).then(value => {
    console.log(value); //这里的value是上一个then返回的"then1" 默认是成功状态
}, reason => {
    console.log(reason); //打印then1
})

其他类型的promise封装
promise对象还可以封装成
{
then(resolve, reject) {
resolve(“这是对象”);
}
}
这样的形式。例如:

new Promise(resolve => {
    resolve("resolve");
}).then(
    value => {
        return {
            then(resolve, reject) {
                resolve("这是对象");
            }
        } //这样的对象会被封装成promise
    },
    reason => {
        return "reason1"
    }).then(
    value => {
        console.log(value); //这里的value是上一个then返回的promise对象中的值 即“这是对象”
    },
    reason => {
        console.log(reason);
    })

**promise中catch的使用 **
可以在then后面加上catch进行错误处理。
reason没有捕捉到的错误或者是没有写reason进行错误处理,则会进入到catch中进行错误处理。例如:

new Promise((resolve, reject) => {
    //resolve和reject中的参数会传递到then中
    //resolve("成功状态");
    reject("拒绝状态");
}).then(
    value => {
        console.log(value);
    }
    //下面这里没有写错误处理
    //但是有catch 所以不会报错
    //catch会进行错误处理
).catch(
    error => {
        console.log(error);
    }
)

promise中finally的使用
finally中的代码始终都会被执行,不管是成功还是失败

const promise = new Promise((resolve, reject) => {
    resolve("resolve");
    //reject("reject");
})
.then(msg => {
    console.log(msg);
})
//捕捉错误
.catch(error => {
    console.log(error);
})
.finally(() => {
    console.log("finally中永远会执行");
})

promise异步加载图片

function loadImage(src) {
    return new Promise((resolve, reject) => {
        const image = new Image();
        image.src = src;
        image.onload = () => {
            resolve(image);
        }
        image.onerror = () => {
            reject("加载失败")
        };
        //为什么下面的写法不行
        //image.onerror = reject("加载失败");
        document.body.appendChild(image);
    })
}
loadImage("images/img1.jpeg").then(image => {
    image.style.width = "100px";
    image.style.height = "100px";
    image.style.border = "solid 10px red";
});

在这里插入图片描述
下面是阮一峰博客上面的写法

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    const image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

用promise封装settimeout定时器

宏任务和微任务

js是单线程的,同步的任务进入主线程,异步的任务进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入Event Queue。(宏任务和微任务是不同的Event Queue)。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)。
在这里插入图片描述
js遇到宏任务先执行宏任务,将宏任务放入eventquene任务队列,再执行微任务,将微任务放入eventquene任务队列。但是这两种任务的任务队列不是一样的。当主线程的任务执行完后,先寻找微任务去执行,再寻找宏任务去执行。
在这里插入图片描述
宏任务一般是:script中的整体代码,setTimeout(settimeout不是直接的把你的回掉函数放进上述的异步队列中去,而是在定时器的时间到了之后,把回掉函数放到执行异步队列中去。如果此时这个队列已经有很多任务了,那就排在他们的后面。这也就解释了为什么setTimeOut为什么不能精准的执行的问题了),setInterval
微任务一般是:Promise,process.nextTick
promise中的回调函数是在微任务中的,其他的是在主线程中。例如:

//1
setTimeout(() => {
    console.log("settimeout"); //4 这是在宏任务中
})
new Promise(resolve => {
    resolve();//创建微任务 这个执行了才会执行回调函数中表示成功的代码
    console.log("promise"); //1 注意!!这是在主线程中
}).then(
    value => {
        console.log("成功"); //3 这里的回调函数是在微任务中
    }
);
console.log("主任务"); //2 主线程


//2
new Promise(resolve => {
    setTimeout(() => {
        console.log("settimeout"); //3
        resolve();//创建微任务 这个执行了才会将then里面的函数加入到微任务中
    }, 0)
    console.log("promise"); //1
}).then(
    value => {
        console.log("成功"); //4
    }
);
console.log("主任务"); //2

ES6中的Set()和Map()方法

  • Set

Set集合是一种无重复元素的列表

声明一个set集合

let s = new Set();
let s1 = new Set([1,2,3,4,5]);

求元素的个数

console.log(s1.size);

添加元素

s1.add('55');

删除元素

s1.delete(1);//参数是set集合的内容 不是索引

检测set集合中是否存在某个值,存在返回true,不存在返回false

console.log(s1.has('55'))

清空元素

s1.clear();

遍历

//注意这里是of不是in!!!
for(let v of s1){
  console.log(v);
}

//或者
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
	//forEach是iterable内置的方法,它接收一个函数,每次迭代就自动回调该函数。
    // element: 指向当前元素的值
    // index: 指向当前索引
    // array: 指向Array对象本身
    alert(element);
});
  • Set对象的作用

数组去重

var arr = [1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 8];
var set = new Set(arr);
console.log(...set);//打印 1 2 3 4 5 6 7 8
//或者
//arr = Array.from(set);//Array.from方法会将一个类数组对象或者可遍历对象(例如set集合,字符串,键值对对象(里面必须要含有length属性用来指定数组的长度))转换成一个真正的数组
//console.log(arr);打印 [1,2,3,4,5,6,7,8]

交集

let arr = [1,2,3,4,5,4,3,2,1];
let arr2 = [4,5,6,5,6];
let result = [...new Set(arr)].filter(item=>{
      let s2 = new Set(arr2); // 4,5,6
      if(s2.has(item)){
        return true;
      }else{
        return false;
      }
    })
console.log(result)//打印 [4,5]

并集

let arr3 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let arr4 = [4, 5, 6, 5, 6];
//注意Set()括号里面是一个数组!!!这里是两个数组合并 要注意用[]括起来!!!
let set2 = new Set([...arr3, ...arr4]);
console.log(...set2);//打印 1 2 3 4 5 6

差集

let arr = [1,2,3,4,5,4,3,2,1];
let arr2 = [4,5,6,5,6];
let diff = [...new Set(arr)].filter(item=> !(new Set(arr2).has(item)))
console.log(diff);//打印 [1,2,3]
  • Map

Map集合内含有多组键值对,集合中每个元素分别存放着可以访问的键名和它对应的值
键名的等价性是通过调用Object.is()方法实现的,所以数字5和字符串5会被识别为两种类型,可以分别作为独立的两个键出现在程序中。

声明一个Map

let m = new Map();

添加元素

m.set('name','galaxy');
m.set('change',function(){
	console.log('我们可以改变你')
})

获取元素的个数

console.log(m.size);

删除元素

m.delete('name');

获取元素

console.log(m.get('change'));

清空Map

m.clear()

遍历

for(let v of m){
  console.log(v);
}

ES6中Map相对于Object对象有几个区别:

  • Object对象有原型, 也就是说他有默认的key值在对象上面,
    除非我们使用Object.create(null)创建一个没有原型的对象;
  • 在Object对象中, 只能把String和Symbol作为key值, 但是在Map中,key值可以是任何基本类型(String,
    Number, Boolean, undefined, NaN….),或者对象(Map, Set, Object, Function ,
    Symbol , null….);
  • 通过Map中的size属性, 可以很方便地获取到Map长度, 要获取Object的长度, 你只能用别的方法了;
      Map实例对象的key值可以为一个数组或者一个对象,或者一个函数,比较随意
    ,而且Map对象实例中数据的排序是根据用户push的顺序进行排序的, 而Object实例中key,value的顺序就是有些规律了,
    (他们会先排数字开头的key值,然后才是字符串开头的key值);

typeOf和instanceOf

  • typeOf

typeOf的返回值是一个字符串,说明运算符的类型
typeof 一般只能返回如下几个结果:“number”、“string”、“boolean”、“object”、“function” 和 “undefined”。

运算数为数字 typeof(x) = “number”

字符串 typeof(x) = “string”

布尔值 typeof(x) = “boolean”

对象,数组和null typeof(x) = "object"

函数 typeof(x) = “function”

若运算数未定义,则返回“undefined”

若运算数是Symbol类型,则返回“symbol”

console.log(typeof Undefined); //undefined
let a = Symbol();
console.log(typeof a); //symbol

我们可以使用 typeof 来获取一个变量是否存在,如 if(typeof a!=“undefined”){alert(“ok”)},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错,对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性

  • instanceOf
    instanceof 运算符用来判断一个变量是否是某个对象的实例
    语法:object instanceof constructor
    参数:object(要检测的对象.)constructor(某个构造函数)
    描述:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
    例如:a instanceof b?alert(“true”):alert(“false”); //a是b的实例?真:假
:var a=new Array();
alert(a instanceof Array); // true,
同时 alert(a instanceof Object) //也会返回 true;
这是因为 Array 是 object 的子类。

再如:function test(){};
var a=new test();
alert(a instanceof test) 会返回true

在这里插入图片描述
以上图为参考

// 定义构造函数
function C(){} 
function D(){} 

var o = new C();

// true,因为o是C的实例 o在C的原型链上
o instanceof C; 

// false,因为 o不是D的实例
o instanceof D; 

o instanceof Object; // true,因为o的原型链上存在Object
C.prototype instanceof Object // true,同上

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype指向了一个空对象,o此时不在C的原型链上

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true

判断数组的四种方法

  • instanceof
let a = [];
a instanceof Array; //true
  • constructor
let a = [1,3,4];
a.constructor === Array;//true
  • Object.prototype.toString.call()
let a = [1,2,3]
Object.prototype.toString.call(a) === '[object Array]';//true
  • Array.isArray()
let a = [1,2,3]
Array.isArray(a);//true

Boolean()函数

可以对任何数据类型的值调用Boolean()函数,并且总会返回一个Boolean值。
返回的值是true还是false,取决于要转换值的数据类型及其实际值。下表给出了各种数据类型及其对应转换规则
先记住值为false的参数有哪些
在这里插入图片描述

Number()函数

转换规则:

  • 如果是Boolean值,true和false分别被转换为1和0
  • 如果是数字值,简单的传入和返回
  • 如果是null值,返回0
  • 如果是undefined,返回NaN
  • 如果是字符串,遵循下列规则:
  • 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值,即"1"会变成1,"123"会变成123,而"011"会变成11(前导的零被忽略了);
  • 如果字符串中包含有效的浮点格式,如"1.1",则将其转换为对应的浮点数值(同样会忽略前导零)
  • 如果字符串包含有效的十六进制格式,例如"0xf",则将其转换为相同大小的十进制整数值
  • 如果字符串是空的(不包含任何字符),则将其转换为0
  • 如果字符串中包含除上述字符格式之外的字符,则将其转换为NaN
  • 如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值.如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串
var num1 = Number("Hello world!");//NaN
var num2 = Number("");//0
var num3 = Number("000011");//11
var num4 = Number(true);//1
console.log(Number(undefined));//NaN
console.log(Number(11.22));//11.22
console.log(Number(0x16));//22

isNaN()函数

NaN和任何数都不相等,包括它本身
NaN(not a number)是Number类型中的中一个特殊的属性,表示非数字。可以通过Number.NaN来访问
isNaN() 函数用于检查其参数是否是非数字值
如果参数值为 NaN 或字符串、对象、undefined等非数字值则返回 true, 否则返回 false。
需要注意的是,isNaN() 函数其实并不能像它的描述中所写的那样,数字值返回 false,其他返回 true。

实际上,它是判断一个值能否被 Number() 合法地转化成数字。

这中间有什么区别呢,主要提现在一些特别的情况如下:

**1、数字形式的字符串。**例如 “123”、"-3.14",虽然是字符串型,但被 isNaN() 判为数,返回 false。(“12,345,678”,“1.2.3” 这些返回 true)
2、空值。 null、空字符串""、空数组[],都可被Number()合法的转为0,于是被isNaN认为是数,返回false。(undefined、空对象{}、空函数等无法转数字,返回true)
**3、布尔值。**Number(true)=1,Number(false)=0,所以isNaN对布尔值也返回false。
**4、长度为 1 的数组。**结果取决于其中元素,即:isNaN([a])=isNaN(a),可递归。例如isNaN([[“1.5”]])=false。
**5、数字特殊形式。**例如"0xabc"、“2.5e+7”,这样的十六进制和科学计数法,即使是字符串也能转数字,所以也返回false。
可能还有其他情况,一时想不到了。

总之,很多时候不能用单纯用 isNaN() 取判断。

比如一个空值或者数组,甚至是包含字母和符号的字符串,它都有可能告诉你这是数值。还是要结合具体情况使用。

ajax

  • 定义及作用

定义:Ajax(Asynchronous Java and XML的缩写)是一种异步请求数据的web开发技术,在不需要重新刷新页面的情况下,Ajax 通过异步请求加载后台数据,并在网页上呈现出来。
作用:提高用户体验,减少网络数据的传输量

  • 原理
    在这里插入图片描述

  • ajax涉及的知识点

  • readyState:xhr的属性 可以知道当前请求所处的状态

    0-(未初始化)还没有调用open()方法

    1-(启动)已调用open()方法,但尚未调用send()方法

    2-(发送)已调用send()方法,但尚未接收到响应

    3-(接收)已经接收到部分响应数据

    4-(完成)已经接收到全部响应数据,而且已经可以在客户端使用了

  • status:HTTP状态码 根据响应状态判断请求是否成功

    1XX:信息性状态码 ,表示接收的请求正在处理

    2XX:成功状态码 , 表示请求正常处理

    3XX:重定向状态码 ,表示需要附加操作来完成请求

    4XX:客户端错误状态 ,表示服务器无法处理请求

    5XX:服务器错误状态 ,表示服务器处理请求出错

  • get和post的区别
    在这里插入图片描述
    而post请求的参数放在send()里面
    xhr对象的setRequestHeader()方法的请求头:

  • 原生JS封装ajax

<script>
    //url type data 这三个是必须的
    function ajax(options) { 
        //调用函数时如果options没有指定,就给它赋值{},一个空的Object
        options = options || {};
        // 请求格式GET、POST,默认为GET
        options.type = (options.type || "GET").toUpperCase();
        //响应数据格式,默认json
        options.dataType = options.dataType || "json";
        //初始化同步或异步请求 默认为异步
        options.async = options.async || true;
        //格式化参数
        var params = formatParams(options.data);

        var xhr; //创建对象
        //考虑兼容性
        if (window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else if (window.ActiveObject) { //兼容IE6以下版本
            xhr = new ActiveXobject('Microsoft.XMLHTTP');
        }

        //----------启动并发送一个请求----------
        if (options.type == "GET") {
            xhr.open("GET", options.url + '?' + params, options.async);
            //设置超时
            xhr.timeout = 20000;
            xhr.ontimeout = function() {
                console.log('connect timeout');
            }
            xhr.send(null);
        } else if (options.type == "POST") {
            //"方式" "地址" "标志位"
            xhr.open("post", options.url, options.async); //初始化请求
            xhr.timeout = 20000;
            xhr.ontimeout = function() {
                console.log('connect timeout');
            }
            //设置表单提交时的内容类型
            //Content-type:数据请求的格式
            xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //设置http头信息
            xhr.send(params); //发送请求
        }

        //可以通过这个设置超时
        //设置有效时间
        // setTimeout(() => {
        //     if (xhr.readyState != 4) {
        //         xhr.abort(); //终止ajax异步请求
        //     }
        // }, options.timeout);

        //格式化参数
        function formatParams(data) {
            var arr = [];
            for (var key in data) {
                //encodeURIComponent()把字符串作为URL组件进行编码
                arr.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[name]));
            }
            //防止页面缓存
            //浏览器为了提高用户访问同一页面的速度,会对页面数据进行缓存。当url请求地址不变时,
			//有时候会导致浏览器不发送请求,直接从缓存中读取之前的数据。
			//如果数据改变了,而没加随机数,读取的数据会跟之前一样。
			//加上随机数,就是欺骗浏览器url改变了,会每次都向服务器发送请求而不去读缓存
            arr.push(("randonNumber=" + Math.random()).replace(".", ""));
            return arr.join("&");
        }

        //----------接收----------
        //options.success成功之后的回调函数  options.error失败后的回调函数
        //xhr.responseText,xhr.responseXML  获得字符串形式的响应数据或者XML形式的响应数据
        //必须要在调用open()之前指定onreadystatechange时间处理程序才能确保跨浏览器兼容性
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                var status = xhr.status;
                if (status >= 200 && status < 300 || status == 304) {
                    options.success && options.success(xhr.responseText, xhr.responseXML);
                } else {
                    options.error && options.error(status);
                }
            }
        }

    }

    //基本的使用实例
    ajax({
        url: "http://server-name/login",
        type: 'post',
        data: {
            username: 'username',
            password: 'password'
        },
        dataType: 'json',
        //可以通过timeout设置超时
        //timeout: 10000,
        contentType: "application/json",
        success: function(data) {  //服务器返回响应,根据响应结果,分析是否登录成功
        },
        //异常处理
        error: function(e) {
            console.log(e);
        }
    })
</script>

创建xhr对象之后,要指定onreadystatechange方法,然后调用open()方法,然后调用setRequestHeader()方法,然后再调用send()方法,调用overrideMimeType()方法必须要在send()方法之前,onprogress()方法要在open()之前,要按这个顺序来

用promise实现对ajax的封装

const myAjax = function(url) {
    const promise = new Promise(function(resolve, reject) {
        //声明一个XMLHttpRequest对象
        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onreadystatechange = function() {
            if (this.readyState !== 4) {
                return;
            }
            if (this.status === 200) {
                resolve(this.response);
            } else {
                reject(new Error(this.statusText));
            }
        };;
        xhr.responseType = "json";
        //设置请求头 Accept:浏览器能够处理的内容类型
        xhr.setRequestHeader("Accept", "application/json");
        xhr.send();

    });

    return promise;
};

myAjax("/posts.json").then(function(value) {
    console.log('Contents: ' + value);
}, function(reason) {
    console.error('出错了', reason);
});
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值