JS常用基础

338 阅读14分钟

1、常用概念

  • typeof : 获取类型
    let age = 10;
    console.log(typeof age);
    //打印结果
    number
    

1.1、数据类型

  • Null : 值被定义了,但定义为空值没有值的变量
  • Undefined : 表示缺少值,此处应该有一个值,未定义的变量

1.2、字符串

1.2.1、字符串方法
  • 常规方法
    • .length : 获取长度
    • .toLowerCase() : 转小写(不改变原有字符串
    • .toUpperCase() : 转大写
      let fullName = 'L' + ' ' + 'z';
      let result = fullName.toLowerCase();
      console.log(result, fullName);
      
    • .includes() : 是否包含某个字符,返回boolean值
  • 查询字符位置
    • .indexOf() : 获取字符第一次出现的位置
    • .lastIndexOf : 获取字符最后出现的位置
      let email = '1556666666@qq.coM';
      let index = email.indexOf('6');
      let lastIndex = email.indexOf('6');
      console.log(index,lastIndex);
      
  • 截取字符串
    • .slice() : 截取字符串(起始位置,结束位置)
      let result = email.slice(0, 5);
      console.log(result);
      
    • .substr() : 截取字符串(起始位置,向后多少位)
      let result = email.substr(2, 5);
      console.log(result);
      
  • 替换字符串
    • .replace() : 替换字符,仅替换第一次出现的
      let result = email.replace('M', 'm');
      result = result.replace('q', 'Q');
      console.log(result);
      
1.2.2、模板字符串
  • 比 "+号" 更灵活的字符串组合方式,使用反引号 ` 定义模板字符串,${变量名}插入变量名

    const myName = 'LZ';
    const myAge = '5';
    const mySex = '男生';
    let result = `我的名字叫${myName},今年${myAge}岁了,是个${mySex}`;
    console.log(result);
    
  • 创建HTML模板(后续可用于插入到html文件中)

    let html = `
        <h2>${myName}</h2>
        <p>${myAge}</p>
        <span>我的性别是${mySex}</span>
    `;
    

1.3、数字

1.3.1、运算符
  • ** : 次方
    //6的3次方
    let result = 6 ** 3;
    console.log(result);
    
1.3.2、NaN
  • Not a Number,当计算数字时出现了非数字量时出现的异常
    //数字与字符串做运算会出现 NaN
    console.log(10 / 'lz');
    

1.4、数组

  • .join() : 将数组中的内容添加指定的分隔符转换成字符串
    let users = ['lz',25,'男','lz'];
    let result = users.join(',');
    console.log(result);
    
  • indexOf() : 查询内容在数组中第一次出现的位置(没有的话返回-1
    let index = users.indexOf('lz');
    console.log(index);
    
  • .includes() : 是否包含某个元素,返回boolean值
  • .concat() : 连接数组
    let result = users.concat(['读书' , 10]);
    console.log(result);
    
  • 增删数组
    • .push() : 在尾部追加元素,返回内容为新数组长度改变原有数组
      let result = users.push('跑步');
      console.log(result);
      //打印结果
      5
      
    • .pop() : 删除尾部元素,返回内容为被删除元素改变原有数组
      let result = users.pop();
      console.log(result);
      //打印结果
      lz
      

1.5、函数

  • 函数声明
    function func1(){
        console.log('func1');
    };
    func1();
    
  • 函数表达式
    //设置形参,并且为time设置默认值
    const func2 = function(name , time = 10){
        console.log(`My Name is ${name},this time is ${time} o'clock`);
    };
    func2('LZ');
    
    //打印结果
    My Name is LZ,this time is 10 o'clock
    
  • 函数声明与函数表达式的区别
    • 函数声明会被编译器提升到顶部,即写在最下边也能调用成功,但函数表达式如果写在调用方法之后会报错
1.5.1、回调函数
  • 在一个函数完成执行后执行的函数(函数做参数
    const myFunc = (callback) => {
        let value = 10;
        callback(value);
    };
    
1.5.2、.foreach()
  • 遍历内容
  • .foreach() 中放函数方法,可直接写也可提取出去;可有3个参数:元素、角标、整体集合
    let personArr = ['张三','李四','王五',['木头六','雀斑七']];
    personArr.forEach((person, index, numberArr) => {
        console.log(`${person} - ${index} - ${numberArr}`);
    });
    
    //打印结果
    张三 - 0 - 张三,李四,王五,木头六,雀斑七
    李四 - 1 - 张三,李四,王五,木头六,雀斑七
    王五 - 2 - 张三,李四,王五,木头六,雀斑七
    木头六,雀斑七 - 3 - 张三,李四,王五,木头六,雀斑七
    

1.6、对象字面量

  • 创建对象,可添加方法,但要注意this关键字时不能用在箭头函数中,简写可省略冒号与function
    let user = {
        name : 'LZ',
        hobbies : ['Sing','Jump','Rap'],
        eat : function (food) {
            console.log(`吃${food}`);
        },
        play : (sport) => {
            console.log(`玩${sport}`);
        },
        //简写方法,省略 冒号与function
        enjoy(name) {
            this.hobbies.forEach((hobby) => {
                console.log(`${name}${hobby}兴趣`);
            });
        },
        //错误写法,箭头函数中不能用this
        mistakeEnjoy : (name) => {
            this.hobbies.forEach((hobby) => {
                console.log(hobby);
            });
        }
    };
    
    user.eat('小笼包');
    user.play('篮球');
    user.enjoy('LZ');
    user.mistakeEnjoy('LZ');
    
    //打印结果
    吃小笼包
    玩篮球
    LZSing兴趣
    LZJump兴趣
    LZRap兴趣
    Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'forEach')
        at mistakeEnjoy (/Volumes/Disk_D/js test/sandbox.js:74:22)
        at <anonymous> (/Volumes/Disk_D/js test/sandbox.js:83:6)
    

1.7、Math

  • Math.round() : 四舍五入
  • Math.floor() : 向下取整
  • Math.ceil() : 向上取整
  • Math.random() : 0 ~ 1间随机数

2、DOM(Document Object Model)

2.1、查询选择器

2.1.1、.querySelector()
  • 查询输入的条件下,第一次出现的内容
    //CSS
    <body>
        <div>
            <h1>Hello World</h1>
            <p>p标签</p>
            <p class="pp">我的p标签</p>
        </div>
        <div class="pp">第二个div</div>
    
        <script src="sandbox.js"></script>
    </body>
    
    • 按标签查询 : 直接填入标签名
      //打印第一次出现的 p标签 内容
      const paragraph = document.querySelector('p');
      console.log(paragraph);
      
      //打印内容
      <p>p标签</p>
      
    • 按类名查询 : .号开始
      //查询类名为 pp 的
      const paragraph = document.querySelector('.pp');
      console.log(paragraph);
      
      //打印内容
      <p class="pp">我的p标签</p>
      
    • 重复类名查询 : 标签名.类名精确查询
      //查询类名为 pp 的 div 标签
      const paragraph = document.querySelector('div.pp');
      console.log(paragraph);
      
      //打印内容
      <div class="pp">第二个div</div>
      
  • .querySelectorAll() : 查询输入的条件下,所有出现的内容,返回 节点列表,类似于数组,可以使用foreach遍历
2.1.2、其他查询选择器
  • .getElementById()
    • 通过Id唯一获取,返回节点
  • .getElementsByClassName()
    • 通过类名获取HTMLCollection集合
  • .getElementsByTagName()
    //获取 p标签
    const paragraph = document.getElementsByTagName('p');
    console.log(paragraph);
    
    //打印结果
    HTMLCollection [p.pp]
    
    • 通过标签获取 HTMLCollection 集合
节点列表与HTMLCollection区别
  • DOM树中,节点列表 可以包含 元素文本节点,而 HTMLCollection 只包含 HTML元素集合,不包含 文本节点
  • 节点列表 类似数组,可以使用foreach遍历HTMLCollection 是元素集合,不能使用foreach方法遍历
  • HTMLCollection可以通过Array.from()转化成数组,从而使用 .foreach()
    //不改变原有结构
    Array.from(document.getElementsByTagName('p'));
    

2.2、内容修改

  • .innerText : 文本操作
    • .textContent的异同:
      • 都是获取文本的操作
      • .innerText 获取不到内部包含隐藏属性(style ="display:none")的标签的标签,但 .textContent 可以
        //.innerText获取不到这种
        <p>标签<span style="display:none">隐藏标签</span></p>
        
      • 平时可以多用 .textContent
  • .innerHTML : 元素操作
    //替换 p标签
    const contents = document.getElementsByClassName('pp');
    contents[0].innerHTML = '<p>替换的p标签</p>';
    
2.2.1、.Attribute()
  • 获取元素属性值,用于对属性进行操作,可用性不高,因为会将属性值整个覆盖,导致原有设置失效
  • .getAttribute() : 获取属性值
  • .setAttribute() : 设置属性值
示例
//CSS创建个a标签
<body>
    <a href="https://www.bilibili.com">哔哩哔哩链接</a>

    <script src="sandbox.js"></script>
</body>
const contents = document.getElementsByTagName('a');
console.log(contents[0].getAttribute('href'));

//对多种属性进行替换
contents[0].innerText = '百度链接';
contents[0].setAttribute('href','https://www.baidu.com');
contents[0].setAttribute('class','myClass');
contents[0].setAttribute('style','color:green');

image.png

2.2.2、.style.xx
  • 通过.style.获取多种属性进行设置,相比 Attribute 好处是不会整体覆盖,增量修改
  • 也不会大量使用,因为一个个设置效率太低,所以样式的设置一般设置类样式,然后通过将元素加入不同的类中实现
const title = document.querySelector('p');
title.style.color = 'red';
title.style.margin = '100px';
2.2.3、增加、删除类
  • .classList : 类列表
    • .add() : 添加类
    • .remove() : 删除类
    • .toggle() : 切换,已有则移除,没有则添加
//增加myClass类,在CSS中寻找并实现这个类的样式
const title = document.querySelector('a');
title.classList.add('myClass');
title.classList.remove('myClass');
title.classList.toggle('myClass');

2.3、相关元素

  • 父元素、子元素、兄弟元素
const title = document.querySelector('a');

//父元素
console.log(title.parentElement);
//子元素
console.log(title.children);
//下一个兄弟元素
console.log(title.nextElementSibling);
//上一个兄弟元素
console.log(title.previousElementSibling);

3、事件

  • addEventListener() : 添加事件监听
  • 执行函数中可以提供事件event,通过.target可以定位点击的目标
const title = document.querySelector('a');

title.addEventListener('click', (e) => {
    e.target.style.textDecoration = 'line-through';
});

3.1、添加删除元素

  • .append() : 尾部追加、.prepend() : 头部追加
const title = document.querySelector('a');
title.addEventListener('click', (e) => {
    //innerHTML方式增加
    title.innerHTML += '<li>新元素</li>';
    //创建Element追加
    const li = document.createElement('li');
    li.textContent = '另一个新元素';
    title.prepend(li);
});

3.2、代理和冒泡

  • 事件冒泡 : 事件会向上传递,点击子元素时,父元素也会响应事件

    const title = document.querySelector('a');
    title.addEventListener('click', (e) => {
        //阻止事件响应
        e.stopPropagation();
    });
    
  • 事件代理 : 可以通过将事件添加到父元素,具体哪个子元素响应的定位,用e.target.tagName判断,这样可以对所有兄弟元素有相同操作,不会出现新添加的兄弟元素响应不了事件的情况

    //CSS样式
    <body>
        <a href='https://www.bilibili.com'>哔哩哔哩链接</a>
        <li>原有li</li>
        <button>添加li元素</button>
    
        <script src="sandbox.js"></script>
    </body>
    
    const title = document.querySelector('a');
    const btn = document.querySelector('button');
    btn.addEventListener('click',(e)=>{
        const li = document.createElement('li');
        li.textContent = '新元素';
        title.prepend(li);
    });
    
    const mybody = document.querySelector('body');
    //监听添加到父元素,但响应在子元素,通过 e.target.tagName 区分具体是哪个子元素
    mybody.addEventListener('click', (e)=>{
        if (e.target.tagName === 'LI') {
            e.target.remove();
        }
    });
    

3.3、各种事件

  • click : 点击事件
  • copy : 被copy内容时
  • mousemove : 鼠标在元素上移动时
element.addEventListener('click', (e)=>{});
element.addEventListener('copy', (e)=>{});
element.addEventListener('mousemove', (e)=>{});

4、表单

4.1、表单提交事件
<body>
<form action="" class="signup-form">
    <input type="text" name="userName" placeholder="姓名">
    <input type="submit" value="提交">
</form>

<script src="sandbox.js"></script>
</body>
const form = document.querySelector('.signup-form');
form.addEventListener('submit',(e)=> {
    //禁止点击提交按钮后的刷新动画
    e.preventDefault();
    //CSS中设置name和id为userName 这里点语法都能调用成功
    console.log(form.userName.value);
});
4.2、正则表达式验证提交内容
  • 正则表达式以 // 包裹中间内容表示

    • [] : 表示允许的 符号范围
    • {} : 表示 限定位数
    • ^ : 表示以后边的 限定内容开头
    • $ : 表示以后边的 限定内容结尾
    • .test() : 对内容进行正则校验,返回boolean值
    const username = '1234myuser';
    //以数字0-9开头,最少2位,最多4位
    //以大写或小写的字母结尾,最少6位
    const pattern = /^[0-9]{2,4}[a-zA-Z]{6,}$/;
    
    //.test()方法对内容进行正则验证
    let result = pattern.test(username);
    console.log(result);
    

    注 : 如果不加 ^$ ,则只是检查字符串中是否包含符合条件的内容

  • 规则与验证可以查看 正则表达式在线网站

4.3、监听键盘输入
  • id或name 为userName的 input标签 进行监听,监听关键字 'keydown'为按下'keyup'为按钮弹起'keypress'为整个按完过程
const form = document.querySelector('.signup-form');
//监听键盘输入
form.userName.addEventListener('keydown',(e)=> {
    const pattern = /^[0-9]{2,4}[a-zA-Z]{6,}$/;
    if (pattern.test(e.target.value)) {
        //正则匹配成功设置class为success,是预设的匹配成功时的CSS样式
        form.userName.setAttribute('class','success');
    } else {
        form.userName.setAttribute('class','error');
    }
});

5、数组方法

5.1、.filter()

  • 过滤,不破坏原有数组
const scores = [12,24,6,50,31,5];
const filterScores = scores.filter((score) => {
    //返回return值为true的内容
    return score > 10;
});

console.log(filterScores);

//打印结果
[12, 24, 50, 31]

5.2、.find()

  • 只返回第一个return为true的内容
const scores = [12,24,6,50,31,5];
const findScore = scores.find((score) => {
    //返回return值为true的内容
    return score > 10;
});

//打印结果
12

5.3、.map()

  • 映射,可对元素进行处理
const fruits = [
    { name: 'apple', salePrice: 10 },
    { name: 'orange', salePrice: 6 },
    { name: 'banana', salePrice: 4 },
    { name: 'grape', salePrice: 15 },
];

const saleFruits = fruits.map((product) => {
    //筛选价格在10元以上的半价
    if (product.salePrice >= 10) {
    
        //这么写会改变原有数组内容
        //return product.salePrice = product.salePrice / 2;
    
        return {name : product.name , salePrice : product.salePrice / 2};
    } else {
        return product;
    }
});
console.log(saleFruits);

5.4、.reduce()

  • 常用3个参数,处理接收参数回调函数接收参数默认值
//myParam为自定义的接收函数处理的参数
const reduceFruitsPrice = fruits.reduce((myParam , fruit) => {
    if (fruit.salePrice > 5) {
        myParam = (Number(myParam) + fruit.salePrice).toString();
    }
    return myParam;
    
// '0'是用户为myParam添加的默认值
}, '0');

5.5、.sort()

  • 排序,改变原有数组,如果不加比值函数,则按位比较ASCII码(数字会出现例如1、20、3、423这种情况)
//普通排序
const scores = [12,24,6,50,31,5];
console.log(scores.sort());

//比值函数
const fruits = [
    { name: 'apple', salePrice: 10 },
    { name: 'orange', salePrice: 6 },
    { name: 'banana', salePrice: 4 },
    { name: 'grape', salePrice: 15 },
];
//注意有{}要加return,拿掉{}可以不加return
fruits.sort((a,b) => {return a.salePrice - b.salePrice});
console.log(fruits);

6、日期与时间

6.1、日期与时间获取

//创建日期对象
const nowDate = new Date();
console.log(nowDate, typeof nowDate);

//日期字符串
console.log('toDateString -- 日期:',nowDate.toDateString());
console.log('toTimeString -- 时分秒:',nowDate.toTimeString());
console.log('toLocaleString -- 本地时间:',nowDate.toLocaleString());
console.log('toLocaleDateString -- 本地日期:',nowDate.toLocaleDateString());
console.log('toLocaleDateString -- 本地时分秒:',nowDate.toLocaleTimeString());

//通过日期对象的方法获取时间的值
console.log('getTime -- since1970:',nowDate.getTime());
console.log('getFullYear -- 年份:',nowDate.getFullYear());
console.log('getMonth -- 月份:',nowDate.getMonth());  //注意获取月份是从0开始,所以使用时要+1
console.log('getDate -- 日期:',nowDate.getDate());
console.log('getDay -- 星期:',nowDate.getDay());      //注意星期天是0
console.log('getHours -- 时:',nowDate.getHours());
console.log('getMinutes -- 分:',nowDate.getMinutes());
console.log('getSeconds -- 秒:',nowDate.getSeconds());

image.png

  • 通过时间戳获取时间
    const timestamps = 1628602116106;
    const time = new Date(timestamps);
    console.log(time);
    

6.2、时间戳日期比较

//自定义一个时间的时间戳
const someDay = new Date('February 1 2022 22:15:30');
const nowDate = new Date();

//计算时间相差的毫秒数
const diff = nowDate.getTime() - someDay.getTime();
const mins = Math.round(diff / 1000 / 60);
const hours = Math.round(mins / 60);
const days = Math.round(hours / 24);
console.log('相差 -- ',mins,'分钟',hours,'小时',days,'天');

//打印结果
相差 -- 111637 分钟 1861 小时 78

6.3、setInterval()

  • 定时器,参数为 方法函数 ,毫秒为单位
const title = document.querySelector('h1');
//定义一个方法函数
const tick = () => {
    const now = new Date();
    const h = now.getHours();
    const m = now.getMinutes();
    const s = now.getSeconds();

    const html = `
    <span>${h}</span>
    <span>${m}</span>
    <span>${s}</span>
    `;
    title.innerHTML = html;
}
//定时器,参数为方法函数,毫秒为单位
setInterval(tick, 1000);

6.4、setTimeOut()

  • 延迟执行,参数为 方法函数 ,毫秒为单位
setTimeOut(() => {
    console.log('延迟2秒执行');
}, 2000);

dayjs

7、异步

7.1、XMLHTTPRequest网络请求

  • XMLHttpRequest() : 创建网络请求
    • 监听 readystatechange 状态,会走4次 readyState
    • .open() : 参数 -- 请求方式接口
    • .send() : 发送网络请求
    • .readyState : 请求状态
    • .status : 响应状态码
    • JSON.parse() : 将内容转换为JSON格式
简单示例
//对网络请求进行封装,请求完毕通过 callback回调函数 返回内容
const requestData = (urlPath, callback) => {
    //网络请求对象
    const request = new XMLHttpRequest();

    //监听请求状态
    request.addEventListener('readystatechange' ,() => {
        //HTTP 响应已经完全接收,并且响应码正常
        if(request.readyState === 4 && request.status === 200) {
            if(request.status === 200) {
                //将返回的字符串转换为JSON
                const jsonData = JSON.parse(request.responseText);
                callback(undefined, jsonData);
            } else {
                callback('无法获取数据', undefined);
            }
        }
    });
    
    //初始化 HTTP 请求参数,例如 URL 和 HTTP 方法,但是并不发送请求
    request.open('GET', urlPath);
    
    //发送 HTTP 请求,使用传递给 open() 方法的参数,以及传递给该方法的可选请求体
    request.send();
}

//调用网络请求,传入接口
requestData('http://jsonplaceholder.typicode.com/todos', (err, data) => {
    console.log(`请求状态:${err}`,'数据为:',data ,typeof data);
});

7.2、Promise

  • 为了实现在 等待其他请求完成后再执行 操作的场景
  • promise对象参数为一个回调函数,这个回调函数有两个参数:resolvereject分别 也都是回调函数两者并不同时执行,成功时执行resolve,失败时执行reject
  • .then() : 等待前面方法执行完毕后再执行,获取promise的 resolve 与 reject 方法可以获取promise中rerurn的内容
  • .catch() : 等待执行监听reject方法
改进示例
//去掉callback参数
const requestData = (urlPath) => {
    //返回 promise对象
    return new Promise((resolve, reject) => {
        const request = new XMLHttpRequest();

        request.addEventListener('readystatechange' ,() => {
            if(request.readyState === 4 && request.status === 200) {
                if(request.status === 200) {
                    const jsonData = JSON.parse(request.responseText);
                    //成功,执行resolve方法
                    resolve(jsonData);
                } else {
                    //失败,执行reject方法
                    reject('无法获取数据');
                }
            }
        });
        request.open('GET', urlPath);
        request.send();
    })
}

//等待请求完毕后 .then()获取 promise 的两个回调函数(此处只写一个), .catch()获取 reject回调函数
requestData('http://jsonplaceholder.typicode.com/users')
.then((data) => {
    console.log('请求数据为:',data ,typeof data);
    return requestData('http://jsonplaceholder.typicode.com/albums');
}).then((data) => {
    console.log('请求数据为:',data ,typeof data);
}).catch((err) => {
    console.log('请求状态为:',err ,typeof err);
});

7.3、fetch()网络请求

  • 无论成功与否,都会返回 promise 对象,与Promise对象resolve与reject方法二选一不同fetch() 即使走 .catch() 方法,还是会走 resolve 方法
7.3.1、Get请求
fetch('http://jsonplaceholder.typicode.com/users')
.then((response) => {
    console.log('resolve:', response);
    
    //直接获取json数据
    return response.json();
}).then((data) => {
    console.log(data);
}).catch((err) => {
    console.log('reject:', err);
});
7.3.2、Post请求
  • 表单提交
    fetch('http://jsonplaceholder.typicode.com/users', {
        method: 'post',
        body: 'userName=13342262638&pwd=123456',
        headers: {
            'Content-Type' : 'application/x-www-form-urlencoded'
        },
    }).then((response) => {
        console.log('resolve:', response);
        return response.text();
    }).then((data) => {
        console.log(data);
    }).catch((err) => {
        console.log('reject:', err);
    });
    
  • JSON提交
    fetch('http://jsonplaceholder.typicode.com/users', {
        method: 'post',
        body: JSON.stringify({
            userName : "LZ",
            pwd : "123456"
        }),
        headers: {
            'Content-Type' : 'application/json',
            'token' : 'myToken'
        },
    }).then((response) => {
        console.log('resolve:', response);
        return response.text();
    }).then((data) => {
        console.log(data);
    }).catch((err) => {
        console.log('reject:', err);
    });
    
其它参数详细配置
  1. method : 请求使用的方法,如 GET、POST, 默认是Get

  2. headers : 请求的头信息,比如可以在里面设置Token、设置content-type类型

  3. credentials : 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie , 必须提供这个选项, 从 Chrome 50 开始,这个属性也可以接受 FederatedCredential 实例或是一个 PasswordCredential 实例

  4. mode : 请求的模式,如 cors、 no-cors 或者 same-origin(默认值)

  5. body : 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息

  6. cache: 请求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached

  7. redirect : 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在Chrome中,Chrome 47之前的默认值是 follow,从 Chrome 47开始是 manual

  8. referrer : 一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client

  9. referrerPolicy : 指定了HTTP头部referer字段的值。可能为以下值之一: no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url

  10. integrity : 包括请求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)

分析总结:
  1. fetch发送请求 默认是不发送cookie 的,不管是同域还是跨域;因此对于那些需要权限验证的请求就可能无法正常获取数据,这时可以配置其 credentials项,其有3个值:
    • omit : 默认值,忽略cookie的发送
    • same-origin : 表示cookie只能同域发送,不能跨域发送
    • include : cookie既可以同域发送,也可以跨域发送

  PS:fetch默认对服务端通过Set-Cookie头设置的cookie也会忽略,若想选择接受来自服务端的cookie信息,也必须要配置 credentials 选项

  1. fetch不支持超时timeout处理

  2. fetch不支持JSONP

  3. 与XHR2一样,fetch也是支持跨域请求的,只不过其跨域请求做法与XHR2一样,需要客户端与服务端支持;另外,fetch还支持一种跨域,不需要服务器支持的形式,具体可以通过其 mode 的配置项来说明。

    • same-origin : 该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response type为basic。
    • cors : 该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response type为cors。
    • no-cors : 该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response type为opaque。(重点!!!)

特别注意:no-cors该模式允许浏览器发送本次跨域请求,但是不能访问响应返回的内容(能访问通接口,但是不能拿到返回值),这也是其response type为opaque透明的原因。

7.4、网络请求错误

  • 根据上面的通用格式,错误肯定是catch中处理,但是 fetch返回的promise对于404、415、500这些错误是获取不到的 ,进入不到catch,catch仅能获取由于网络延迟错误,所以这里需要再次封装一下,获取这些状态,进行throw抛出,让其进入catch即可
    fetch('http://jsonplaceholder.typicode.com/users')
    .then((response) => {
        if (response.status >= 200 && response.status < 300) {
            return response.text();
        }
        const error = new Error(response.statusText);
        error.response = response;
        throw error; //检测到报错会进入到catch中
    }).then((data) => {
        console.log(data);
    }).catch((err) => {
        console.log('reject:', err);
    });
    
  • throw 抛出的错误会走 catch() 方法

7.5、async 与 await

  • async 与 await 同时出现,如果只用了async异步没用await,那么会出现用空内容给变量赋值的情况

  • 与promise一样都是非阻塞的

const requestData = async () => {
    const response = await fetch('http://jsonplaceholder.typicode.com/users');
    
    //通过 throw 手动抛出错误
    if (response.status === 200) {
        throw new Error('无法获取数据');
    }
    const userData = await response.json();

    return userData;
}

requestData().then((data) => {
    console.log(data);
})

8、本地存储

8.1、本地数据增删改查

//存储
localStorage.setItem('myName','lz');
localStorage.mySex = 'male';

//获取
const name = localStorage.getItem('myName');
const sex = localStorage.mySex;
console.log(name,sex);

//删除
localStorage.removeItem('myName');
localStorage.clear();

8.2、格式转换

  • JSON.stringify() : 将json数据转换为字符串(方便存到本地)
  • JSON.parse() : 将字符串转换为json数据(从本地获取使用)

9、ES6

9.1、rest参数、spread语法

  • rest参数 : 可以将不确定数量的参数装入数组中作为参数
  • spread语法 : 将数组内容拆散
  • 使用...变量名方式使用这两种,分散内容会被合成数组,集合类型会被拆分(新创建内容)
//rest参数
const double = (...nums) => {
    console.log(nums);
    return nums.map((num) => num *2);
};
const result = double(1,2,3,4,5,6,7,8);
console.log(result);

//spread语法(数组)
const users = ['张三','李四','王五'];
const members = ['熊大','熊二',...users];
console.log(members);

//spread语法(对象)
const people = {'name' : 'lz', age : 18, job : 'teacher'};
//将对象进行拷贝拆散,并扩展了location内容
const peopleClone = {...people, location: 'beijing'};

console.log(peopleClone);

9.2、Set() : 集合

  • 使用.add()添加元素.delete()删除元素.forEach()遍历
  • 数组允许重复数据Set集合不能有重复数据,因此可以利用该特性来过滤重复数据
const users = ['张三','李四','王五','张三'];
//利用spread语法将Set集合拆到数组中
const uniqueUsers = [...new Set(users)];
console.log(uniqueUsers);

9.3、symbol类型

  • 数据类型中,基本类型属于原始类型Object都属于引用类型,symbol属于原始类型
  • symbol无法创建2个相同的对象,即使构建相同,因此每个symbol都是唯一的
const user = {};
const symbolOne = Symbol('user');
const symbolTwo = Symbol('user');

//不会覆盖,因为symbol作为key是不相同的
user[symbolOne] = 'one';
user[symbolTwo] = 'two';
console.log(user);

//打印结果
{Symbol(user): 'one', Symbol(user): 'two'}