ES6学习笔记

1.什么是ECMA?

ECMA(European Computer Manufacturers Association)中文名称为欧洲计算机制造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。1994 年后该组织改名为 Ecma 国际;
  • ECMAScript:ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化的脚本程序设计语言;

  • 谁在维护 ECMA-262:TC39(Technical Committee 39)是推进 ECMAScript 发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果、谷歌、微软、因特尔等)。TC39 定期召开会议,会议由会员公司的代表与特邀专家出席;
  • 为什么要学习 ES6:ES6 的版本变动内容最多,具有里程碑意义;ES6 加入许多新的语法特性,编程实现更简单、高效;ES6 是前端发展趋势,就业必备技能;
  • ES6 兼容性:查看网址:http://kangax.github.io/compat-table/es6

2.let 关键字

// let关键字使用示例:
let a;// 单个声明
let b,c,d; // 批量声明 
let e = 100; // 单个声明并赋值 
let f = 521, g = 'iloveyou', h = []; // 批量声明并赋值
  • 变量不允许重复声明;
// 1. 不允许重复声明; 
let dog = "狗"; let dog = "狗"; 
// 报错:Uncaught SyntaxError: Identifier 'dog' has already been declared
  • 块儿级作用域(局部变量):只在代码块中有效;
// 2. 块儿级作用域(局部变量); 
{ 
    let cat = "猫"; 
    console.log(cat);
}
console.log(cat); 
// 报错:Uncaught ReferenceError: cat is not defined
  • 不存在变量提升,不允许在定义变量之前使用变量;
consloe.log(son);
let son=15;
  • 不影响作用域链;什么是作用域链:就是代码块内有代码块,上级代码块中的局部变量下级可用。
注意:以后声明变量使用 let 就对了;

3.const 关键字

  • 声明必须赋初始值;

  • 标识符一般为大写(习惯);
  • 不允许重复声明;
  • 值不允许修改:对数组元素的修改和对对象内部的修改是可以的(数组和对象存的是引用地址);

  • 块儿级作用域(局部变量);

注意:声明对象类型使用 const,非对象类型声明选择 let;

4.变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值;
  • 数组的解构赋值:
const F4 = ["大哥","二哥","三哥","四哥"];
let [a,b,c,d] = F4; 
// 这就相当于我们声明4个变量a,b,c,d,其值分别对应"大哥","二哥","三哥","四哥" 
console.log(a + b + c + d); // 大哥二哥三哥四哥
  • 对象的解构赋值:
const F3 = { 
    name : "大哥",
    age : 22, 
    sex : "男",
    xiaopin : function(){ // 常用
        console.log("我会演小品!"); 
    }
}
    let {name,age,sex,xiaopin} = F3; // 注意解构对象这里用的是{}
    console.log(name + age + sex + xiaopin); // 大哥22男 
    xiaopin(); 
// 此方法可以正常调用

5.模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识【esc下方的按键】,特点:
  • 字符串中可以出现换行符;
  • 可以使用 ${xxx} 形式引用变量
声明字符串的方法:单引号('')、双引号("")、反引号(``)

5.1声明

let string = `我也一个字符串哦!`;
console.log(string);

5.2内容中直接出现换行符

// 特性 
// 1、字符串中可以出现换行符 
let str = `<ul>
            <li>大哥</li> 
            <li>二哥</li> 
            <li>三哥</li> 
            <li>四哥</li>
          </ul>`; 
console.log(str);

5.3变量拼接

let s = "大哥"; 
let out = `${s}是我最大的榜样!`;
console.log(out);

6.简化对象写法

ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁;
// 变量和函数 
let name = "訾博";
let change = function(){
    console.log("活着就是为了改变世界!");
}
//创建对象 
const school = { 
    // 完整写法
    // name:name,
    // change:change 
    // 简化写法 
    name, 
    change, 
    //声明方法原版:say: function(){console.log("123")}
    // 声明方法的简化
    say(){
        console.log("言行一致!"); 
    } 
}
    school.change(); 
    school.say();

7.箭头函数及其声明特点(=>)

ES6允许使用箭头(=>)定义函数,箭头函数提供了一种更加简洁的函数书写方式,箭头函数多用于匿名函数的定义;

7.1特性

  • 箭头函数的this是静态的,始终指向函数声明时所在作用域下的this的值;
  • 不能作为构造函数实例化对象,即箭头不能声明构造器;
  • 不能使用 arguments 变量;
  • 形参有且仅有一个时,可以省略小括号
    <script>
        // 省略前
        let add = (a) => {
            return a;
        }
        console.log(add(5));
        // 省略后
        let plus = b => {
            return b;
        }
        console.log(plus(77));
    </script>
  • 代码体语句只有一条的时候,可以省略花括号。并且此时return必须省略。此时语句的执行结构就是函数的返回值
// 省略前
let pow = (n) => {
    return n * n;
};
console.log(pow(77));
// 省略后
let pow2 = n => n * n;
console.log(pow(22));

7.2箭头函数实践和应用场景

  • 案例1:点击2s后变色
<div></div>
<script>
    // 需求1:点击div 2s后颜色变成粉色
    let div = document.querySelector('div');
    div.addEventListener('click', function() {
        // 解决方法1:提前保存this的值
        let _this = this;
        // 定时器
        // setTimeout(function() {
        //     // 这里不能用this 点击之后this指向window而不是div
        //     _this.style.background = 'pink';
        // }, 2000)
        // 解决方法2:改成箭头函数
        // 箭头函数里面this时静态的,指向的是“声明时,所在作用域下的this的值,所以指向的是div.addEventListener('click', function()的this”
        setTimeout(() => {
            // 这里不能用this 点击之后this指向window而不是div
            this.style.background = 'pink';
        }, 2000)
    })
</script>
  • 声明一个数组,从数组中返回偶数元素
<script>
    const arr = [1, 6, 9, 12, 55, 100];
    // 原来
    const result1 = arr.filter(function(item) {
        if (item % 2 === 0) {
            return true;
        } else
            return false;
    })
    // 使用箭头函数后
    const result2 = arr.filter(item => item % 2 === 0);
    console.log(result2);
</script>
注意:
  • 箭头函数适合与 this 无关的回调. 定时器, 数组的方法回调
  • 箭头函数不适合与 this 有关的回调. 事件回调, 对象的方法
事件回调:这里的div.addEventListener如果用箭头函数就会让函数里面的this指向window
<script>
    let div = document.querySelector('div');
    div.addEventListener('click', ()=> {
        let _this = this;
    })
</script>

8.函数参数默认值设置

ES允许给函数的参数赋初始值;
//形参初始值 具有默认值的参数, 一般位置要靠后(潜规则) 
function add(a, b, c = 10) {
    return a + b + c;
}
let result = add(1, 2);
console.log(result); // 13
与解构赋值相结合:
function connect({
    host = "127.0.0.1",
    username,
    password,
    port
}) {
    console.log(host)
    console.log(username)
    console.log(password)
    console.log(port)
}
// 调用函数
connect({
    host: 'atguigu.com',
    username: 'root',
    password: 'root',
    port: 3306
})

9.rest参数

ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments;参考文章:https://www.jianshu.com/p/50bcb376a419
<script>
    // ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments; 
    // 1.ES5获取实参的方式 
    function data1() {
    console.log(arguments);
}
data1("大哥", "二哥", "三哥", "四哥");
// 2.ES6的rest参数...args,rest参数必须放在最后面
function data(a, b, ...args) {
    console.log(a);
    console.log(b);
    console.log(args); // fliter some every map
}
data("大哥", "二哥", "三哥", "四哥");
</script>

10.扩展运算符(...)

... 扩展运算符能将数组转换为逗号分隔的参数序列;
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包;
  • 扩展运算符应用
<div></div>
<div></div>
<div></div>
<script>
    //1. 数组的合并 情圣 误杀 唐探 
    const kuaizi = ['王太利', '肖央'];
    const fenghuang = ['曾毅', '玲花'];
    // 1.1传统的合并方式 
    // const zuixuanxiaopingguo = kuaizi.concat(fenghuang); 
    // 1.2扩展运算符合并方式
    const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
    console.log(zuixuanxiaopingguo);

    //2. 数组的克隆 
    const sanzhihua = ['E', 'G', 'M'];
    const sanyecao = [...sanzhihua]; // ['E','G','M'] 
    console.log(sanyecao);

    //3. 将伪数组转为真正的数组 
    const divs = document.querySelectorAll('div');
    const divArr = [...divs];
    console.log(divArr); // arguments
</script>

11.Symbol基本使用

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型;
特点:(1)Symbol 的值是唯一的,用来解决命名冲突的问题(2)Symbol 值不能与其他数据进行运算(3)Symbol 定义的对象属性不能使用for…in循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名
<script>
    //创建Symbol 
    let s = Symbol();
    console.log(s, typeof s);
    let s2 = Symbol('尚硅谷');
    let s3 = Symbol('尚硅谷');
    console.log(s2);
    console.log(s2 == s3); // false
    //Symbol.for 创建 
    let s4 = Symbol.for('尚硅谷');
    let s5 = Symbol.for('尚硅谷');
    console.log(s4);
    console.log(s4 == s5); // true
</script>
// 常见的数据类型
// USONB you are so niubility
// u undefined 
// s string symbol
// o object
// n null number
// b boolean

11.1 Symbol的使用场景:给对象添加属性和方法

  • 方式一
<script>
    // 向对象中添加方法 up down 
    let game = {
        name: '俄罗斯方块',
        up: function() {},
        down: function() {}
    };
    // 我们要往game对象里面添加方法,但是怕game对象已经存在 
    // 同名方法,所以我们这时使用到了Symbol
    // 方式一 
    // 声明一个对象 
    let methods = {
        up: Symbol(),
        down: Symbol()
    };
    game[methods.up] = function() {
        console.log("我可以改变形状");
    }
    game[methods.down] = function() {
        console.log("我可以快速下降!!");
    }
    console.log(game);
</script>
  • 方式二
<script>
    // 向对象中添加方法 up down 
    let game = {
        name: '俄罗斯方块',
        up: function() {},
        down: function() {}
    };
    // 方式二 
    let youxi = {
        name: "狼人杀",
        [Symbol('say')]: function() {
            console.log("我可以发言")
        },
        [Symbol('zibao')]: function() {
            console.log('我可以自爆');
        }
    }
    console.log(youxi);
</script>
  • 调用
let youxi1 = {
    name: "狼人杀",
    [say]: function() {
        console.log("我可以发言")
    },
    [Symbol('zibao')]: function() {
        console.log('我可以自爆');
    }
}
let say = Symbol('say');
youxi1[say]();
总结:为了防止你创建和方法和对象本身的方法冲突,选择在另一个对象中用symbol创建独一无二的方法,用[]调用,不会污染本身对象中的方法

11.2 Symbol的内置属性

除了定义自己使用的 Symbol 值以外,ES6 还提供了 11 个内置的 Symbol 值,指向语言内部使用的方法。可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行;总结:为了防止你创建和方法和对象本身的方法冲突,选择在另一个对象中用symbol创建独一无二的方法,用[]调用,不会污染本身对象中的方法

特别的: Symbol内置值的使用,都是作为某个对象类型的属性去使用;

12.迭代器

遍历器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作;
ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费;原生具备 iterator 接口的数据(可用 for of 遍历)有:Array;Arguments;Set;Map;String;TypedArray;NodeList;
<script>
    // 声明一个数组 
    const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
    // 使用 for...of 遍历数组 
    for (let v of xiyou) {
        console.log(v);
    }
</script>
注意:for(let v in xiyou):v指的是键名key=[0、1、2、3]   ;for of遍历的是键值

12.1 工作原理:

  • 创建一个指针对象,指向当前数据结构的起始位置
  • 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
  • 接下来不断调用 next 方法指针一直往后移动,直到指向最后一个成员
  • 每调用 next 方法返回一个包含 value 和 done 属性的对象
注:需要自定义遍历数据的时候,要想到迭代器;😀
<script>
    // 声明一个数组 
    const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
    let it = xiyou[Symbol.iterator]();
    console.log(it);
    // 调用对象的next方法
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
</script>

12.2自定义遍历对象

<script>
    const banji = {
        name: "终极一班",
        stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
        // 1.首先加上iterator接口
        [Symbol.iterator]() {
            // 索隐变量 对stus进行遍历
            let index = 0;
            return {
                // 2.要有一个next对象
                // 用箭头函数是this为静态变量
                next: () => {
                    if (index < this.stus.length) {
                        const result = {
                            value: this.stus[index],
                            done: false
                        };
                        index++;
                        return result;
                    } else {
                        return {
                            value: undefined,
                            done: true
                        }
                    }
                }
            };
        }
    }
    // 遍历这个对象 返回的是stus数组的对象
    for (let v of banji) {
        console.log(v);
    }
</script>

13.生成器

其实就是一个函数,生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同;
异步编程有 node fs ajax mongodb(数据库)

13.1概念区分

  • 并发:计算机可以同时执行多个任务。比如单核处理器,可以采用分配时间片的方式让两个任务交替进行
  • 并行:多核处理器可以真正实现同一时间执行任务
  • 同步:上一个任务执行结束之后才可以执行下一个任务
  • 异步:任务之间不会相互等待,在运行任务A的时候也可以执行任务b 

13.2基本使用

  • 命名时function和函数名中间要有一个星号
  •  yield是函数代码的分隔符
<script>
    // 命名时function和函数名中间要有一个星号
    function* gen() {
        console.log("hello generator");
    }
    let iterator = gen();
    console.log(iterator); //返回了迭代器对象
    iterator.next(); //才输出
</script>


<script>
    // 命名时function和函数名中间要有一个星号
    // 可以有一个yield语句 yield是函数代码的分隔符 下边代码将函数其分成了四块
    function* gen() {
        console.log(111);
        yield '一只没有耳朵';
        console.log(222);
        yield '一只没有尾部';
        console.log(333);
        yield '真奇怪';
        console.log(444);
    };
    let iterator = gen();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    
    for (let v of gen()) {
        console.log(v);
    }
</script>

13.3生成器函数的参数传递

<script>
    function* gen2(arg) {
        console.log(arg);
        let one = yield 111;
        console.log(one);
        let two = yield 222;
        console.log(two);
        let three = yield 333;
        console.log(three);
    };
    // 获取迭代器对象,可以在对象声明的时候传入实参
    let it = gen2('aaaaa');
    console.log(it.next());

    // next方法可以传入实参 第二个next传入的是第一个yield语句的返回结果
    console.log(it.next("bbbb"));
    // 第三个next传入的是第二个yield语句的返回结果
    console.log(it.next("ccccc"));
    // 第四个next传入的是第三个yield语句的返回结果
    console.log(it.next("dddddd"));
</script>


13.4生成器实例:需求:1s后控制台输出111 再过2s后控制台输出222 再过3s后控制台输出333

  • 方法一:回调地狱
// 方法一:回调地狱
setTimeout(() => {
    console.log(111);
    setTimeout(() => {
        console.log(222);
        setTimeout(() => {
            console.log(333);
        }, 3000)
    }, 2000)
}, 1000);
  • 方法二:设置多个函数
// 方法二:定义三个函数 分别完成三个任务
function one() {
    setTimeout(() => {
        console.log(111);
        iterator.next(); //进入two
    }, 1000)
}

function two() {
    setTimeout(() => {
        console.log(222);
        iterator.next(); //进入three
    }, 2000)
}

function three() {
    setTimeout(() => {
        console.log(333);
        iterator.next(); //结束
    }, 3000)
}

function* gen() {
    console.log("开始喽");
    yield one();
    yield two();
    yield three();
};
// 调用生成器函数
let iterator = gen();
iterator.next(); //刚开始调用“开始喽” 并进入one

13.5生成器函数实例:模拟获取:用户数据 订单数据 商品数据
<script>
    function getuser() {
        setTimeout(() => {
            let data = "用户数据";
            // 调用next方法并将数据传入
            iterator.next(data);
        }, 1000)
    }

    function getorder() {
        setTimeout(() => {
            let data = "订单信息";
            iterator.next(data);
        }, 1000)
    }

    function getgood() {
        setTimeout(() => {
            let data = "商品数据";
            iterator.next(data);
        }, 1000)
    }

    function* gen() {
        let user = yield getuser();
        console.log(user);
        let order = yield getorder();
        console.log(order);
        let good = yield getgood();
        console.log(good);
    };
    // 调用生成器函数
    let iterator = gen();
    iterator.next();
</script>

14.Promise

Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果;
  • Promise 构造函数: Promise (excutor) {};
  • Promise.prototype.then 方法:接受两个参数,且这两个参数都是function方法,如果resolve调用成功,则返回第一个参数的函数;
  • Promise.prototype.catch 方法;用于指定Promise失败的回调;
数据读取成功:
<script>
    // 实例化 Promise对象
    const p = new Promise(function(resolve, reject) {
        setTimeout(() => {
            let data = '数据库中的数据';
            // 调用resolve,这个Promise 对象的状态就会变成成功
            resolve(data);
        }, 1000);
    });
    // 调用Promise对象的then方法,两个参数为函数
    p.then(function(value) {
        // 调用成功
        console.log(value);
    }, function(reason) {
        // 调用失败
    })
</script>

数据读取失败:
<script>
    // 实例化 Promise对象
    const p = new Promise(function(resolve, reject) {
        setTimeout(() => {
            // let data = '数据库中的数据';
            // // 调用resolve,这个Promise 对象的状态就会变成成功
            // resolve(data);
            let err = "数据读取失败";
            // 调用reject,这个Promise 对象的状态就会变成成功
            reject(err);
        }, 1000);
    });
    // 调用Promise对象的then方法,两个参数为函数
    p.then(function(value) {
        // 调用成功
        console.log(value);
    }, function(reason) {
        // 调用失败
        console.log(reason);
    })
</script>

14.1 Promise封装读取文件,在js文件里面,需要nonde.js知识



  • 一般写法



// 1.引入fs模块
const fs = require('fs');

// 2.调用方法读取文件
fs.readFile('/resources/接口文档.md', (err, data) => {
    // 如果失败则抛出错误
    if (err) throw err;
    // 如果没有出错 则输出内容
    console.log(data);
})


  • 封装写法


const p = new Promise(function(resolve, reject) {
    fs.readFile('/resources/接口文档.md', (err, data) => {
        // 判断失败
        if (err)
            reject(err);
        //如果成功
        resolve(data);
    })
})
p.then(function(value) {
    console.log(value.toString());
}, function(reason) {
    console.log("读取失败!");
})

14.2 Promise封装Ajax请求

<script>
    const p = new Promise(function(resolve, reject) {
        // 创建对象
        const xhr = new XMLHttpRequest();
        // 初始化
        xhr.open("GET", "https://api.apiopen.top/getJoke");
        // 发送
        xhr.send();
        // 4、绑定事件,处理响应结果 
        xhr.onreadystatechange = function() {
            // 判断状态 
            if (xhr.readyState == 4) {
                // 判断响应状态码 200-299 
                if (xhr.status >= 200 && xhr.status <= 299) {
                    // 成功 
                    resolve(xhr.response);
                } else { // 失败 
                    reject(xhr.status);
                }
            }
        }
    })
    // 指定回调
    p.then(function(value) {
        console.log(value);
    }, function(reason) {
        console.log(reason);

    })
</script>

14.3 Promise.prototype.then:

<script>
    const p = new Promise((resolve, reject) => {
        setTimeout(function() {
            resolve('用户数据');
            // reject('错了');
        }, 1000)
    });
    // 注意:如果回调函数中返回的结果是 非promise 类型的数据,状态为成功,返回值为对象的成功值resolved
    const result = p.then(function(value) {
        console.log(value);
        // 1.返回的结果是 非promise 类型的数据
        // return 1;

        // 2.返回对象是promise对象 此Promise对象的状态决定上面Promise对象p的状态
        // return new Promise((resolve, reject) => {
        //     // resolved 
        //     resolve('ok');
        //     //  rejected
        //     reject('wrong');
        // })

        // 3.抛出错误
        // 状态:rejected 
        // value:出错了
        throw '出错了';
    }, function(reason) {
        console.warn(reason);
    });
    // 可以链式调用,then里面两个函数参数,可以只写一个
    // p.then(value => {}, reason => {}).then(value => {}, reason => {});

    // 调用then方法,then方法的返回结果是promise对象,对象的状态由回调函数的结果决定;
    console.log(result);
</script>

14.4 Promise实践

  • 回调地狱写法:容易有重名问题
// 1、引入 fs 模块
const fs = require("fs");
// 2、调用方法,读取文件
fs.readFile("resources/text.txt", (err, data1) => {
    fs.readFile("resources/test1.txt", (err, data2) => {
        fs.readFile("resources/test2.txt", (err, data3) => {
            let result = data1 + data2 + data3;
            console.log(result);
        });
    });
});
  • Promise写法:
const p = new Promise((resolve, reject) => {
    fs.readFile("resources/text.txt", (err, data) => {
        resolve(data);
    });
});
p.then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("resources/test1.txt", (err, data) => {
            resolve([value, data]);
        });
    })
}).then(value => {
    return new Promise((resolve, reject) => {
        fs.readFile("resources/test2.txt", (err, data) => {
             // 存入数组 
            value.push(data);
            resolve(value);
        });
    })
}).then(value => {
    console.log(value.join("\r\n"));
})

14.5 catch方法

用于指定Promise失败的回调;
<script>
        const p = new Promise((resolve, reject) => {
            setTimeout(() => {
                // 设置 p 对象的状态为失败 ,并设置失败的值
                reject("出错了");
            }, 1000)
        });
        // 方式1:
        p.then(function(value) {}, function(reason) {
            console.log(reason);
        });
        // 方式2:算是一个语法糖,即使没有catch 用then也可以工作
        p.catch(function(reason) {
            console.log(reason);
        });
    </script>

15.Set集合

ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:
  • size 返回集合的元素个数;
  • add(value):添加某个值,返回 Set 结构本身(可以链式调用)
  • delete(value):删除某个值,删除成功返回true,否则返回false
  • has(value):返回一个布尔值,表示该值是否为Set的成员,有返回true,否则返回false
  • clear(): 将这个Set中的所有元素删除
const mySet = new Set(['a', 'a', 'b', 1, 2, 1])
console.log(mySet)  // {'a', 'b', 1, 2}
myset.add('c').add({'a': 1}) //链式调用
console.log(mySet) // {'a', 'b', 1, 2, 'c', {a: 1}}
console.log(mySet.size) // 6
 
mySet.has(2) // true
  • 初始化
var set = new Set();

15.1 遍历方法

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
由于Set结构没有键名,只有键值(或者说key和value是同一个值),所以keys方法和values方法的行为完全一致。
const set = new Set(['a', 'b', 'c'])
 
for (var item of set.keys()) {
    console.log(item)
}
// a
// b
// c
 
for (var item of set.values()) {
    console.log(item)
}
// a
// b
// c
 
for (var item of set.entries()) {
    console.log(item)
}
// 因为key=value
// ["a", "a"]
// ["b", "b"]
// ["c", "c"]
 
// 直接遍历set实例,等同于遍历set实例的values方法
for (var item of set) {
    console.log(item)
}
// a
// b
// c
 
set.forEach(function(value, key) {
    console.log(key + ' : ' + value)
})
// a: a
// b: b
// c: c

15.2 数组的操作【数组去重、交集、并集、差集】

  • filter函数【过滤】:如果返回的是true 则将这个元素保留在数组中,如果返回的是false,则要将这个元素删除

  • 数组去重
<script>
    let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1, 8, 9, 10];
    let arr2 = [4, 3, 2, 1, 7];
    // 数组去重
    let result1 = [...new Set(arr)];
    console.log(result1);
    // 交集
    let result2 = [...new Set(arr)].filter(item => {
        let s2 = new Set(arr2);
        if (s2.has(item)) {
            return true;
        } else {
            return false;
        }
    })
    console.log(result2);
    // 并集
    let result3 = [...new Set([...arr, ...arr2])];
    console.log(result3);
    //差集 求arr里面有 arr2里面没有的;对arr2里面取反
    let result4 = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
    console.log(result4);
</script>

16.Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历;
Map 的属性和方法:
  • size 返回 Map 的元素个数;
  • set(key, val): 向Map中添加新元素
  • get(key): 通过"键值"查找特定的数值并返回
  • has(key): 判断Map对象中是否有Key所对应的值,有返回true,否则返回false
  • delete(key): 通过"键值"从Map中移除对应的数据
  • clear(): 将这个Map中的所有元素删除
const map = new Map([
    ['Amy', 11],
    ['Sam', 12]
]);
console.log(map); // {"Amy" => 11, "Sam" => 12}
console.log(map.get('Amy')); // 11
 
const map2 = new Map([
    ['Cindy', 13]
])
const map3 = new Map(map2);
console.log(map3.get('Cindy')); // 13
console.log(map3.has('Cindy')); // true
map3.set('Divid', 15)
console.log(map3.get('Divid')); // 15

16.1 循环遍历

  • keys():返回键名的遍历器
  • values():返回键值的遍历器
  • entries():返回键值对的遍历器
  • forEach():使用回调函数遍历每个成员
由于
Set结构没有键名,只有键值(或者说key和value是同一个值),所以keys方法和values方法的行为完全一致。
const map = new Map([
    ['Amy', 11],
    ['Sam', 12]
])
 
for (var key of map.keys()) {
    console.log(key)
}
// "Amy"
// "Sam"
 
for (var value of map.values()) {
    console.log(value)
}
// 11
// 12
 
for (var item of map.entries()) {
    console.log(item)
}
// ['Amy', 11],
// ['Sam', 12]
 
// 方法一:
for (var [key, value] of map.entries()) {
    console.log(key, value)
}
// "Amy" 11
// "Sam" 12
 
// 方法二:for...of...遍历map等同于使用map.entries()
// 方法一和方法二的输出结果一样
for (var [key, value] of map) {
    console.log(key, value);
}
// "Amy" 11
// "Sam" 12

16.2Map与Object区别

  • Map中的键值是有序的,而添加到对象中的则不是
  • Map的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突

17.Class类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已;
  • ES5通过实例化创造对象
<script>
    function Phone(brand, price) {
        this.brand = brand;
        this.price = price;
    }
    // 添加方法
    Phone.prototype.call = function() {
        console.log("打电话");
    }
    // 实例化对象
    let Hawei = new Phone('华为', 5999);
    Hawei.call();
    console.log(Hawei);
</script>
  • ES6
<script>
    class Phone {
        // 构造方法 名字不能修改 会自动执行
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }
        // ES6定义方法必须使用该语法,不能使用ES5的对象完整形式
        call() {
            console.log("我可以打电话");
        }
    }
    let Hawei = new Phone('华为', 5999);
    console.log(Hawei);
</script>

17.1 静态成员

//ES5
<script>
    function Phone() {

    }
    Phone.name = '手机';
    Phone.change = function() {
        console.log("我可以改变世界");
    }
    let nokia = new Phone();
    console.log(nokia.name); // undefined
    //nokia.change(); // 报错:Uncaught TypeError: nokia.change is not a function
    // 注意:实例对象和函数对象的属性是不相通的

    Phone.prototype.size = '5.5';
    console.log(nokia.size);
</script>
//ES6
<script>
    // ES6写法
    class Phone {
        // 静态属性 属于类 而不属于实例对象
        // 静态属性通过类名.方法名访问
        static name = "手机";
        static change() {
            console.log("我可以改变世界!");
        }
    }
    let nokia = new Phone();
    console.log(nokia.name); //undefined
    console.log(Phone.name); //手机
    Phone.change();
</script>

17.2 对象继承

  • ES5
<script>
    // 手机
    function Phone(brand, price) {
        this.brand = brand;
        this.price = price;
    }
    // 添加方法
    Phone.prototype.call = function() {
        console.log("打电话");
    };
    // 智能手机
    function SmartPhone(brand, price, color, size) {
        Phone.call(this, brand, price);
        this.color = color;
        this.size = size;
    }
    // 设置子集构造函数的原型
    SmartPhone.prototype = new Phone;
    SmartPhone.prototype.constructor = SmartPhone;

    // 声明子类方法
    SmartPhone.prototype.photo = function() {
        console.log("拍照");
    }
    SmartPhone.prototype.game = function() {
        console.log("游戏");
    }
    // 实例化对象
    let chuizi = new SmartPhone('华为', 5999, 'black', '5.5');
    console.log(chuizi);
</script>

  • ES6
<script>
    class Phone {
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }
        call() {
            console.log("我可以打电话");
        }
    }
    class SmartPhone extends Phone {
        constructor(brand, price, color, size) {
            super(brand, price);
            this.color = color;
            this.size = size;
        }
        photo() {
            console.log("拍照");
        }
        game() {
            console.log("游戏");
        }
    }
    let chuizi = new SmartPhone('小米', 1999, 'black', '5.5');
    console.log(chuizi);
		
     chuizi.call();
     chuizi.photo();
     chuizi.game();
</script>



17.3   子类对父类的重写

<script>
    class Phone {
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }
        call() {
            console.log("我可以打电话");
        }
    }
    class SmartPhone extends Phone {
        constructor(brand, price, color, size) {
            super(brand, price);
            this.color = color;
            this.size = size;
        }
        photo() {
            console.log("拍照");
        }
        game() {
            console.log("游戏");
        }
        // 就近原则
        call() {
            console.log("我对父类进行重写了");
        }
    }
    let chuizi = new SmartPhone('小米', 1999, 'black', '5.5');
    chuizi.call();
</script>


17.4 class的getter和setter设置

<script>
    // class中的getter和setter设置 
    class Phone {
        get price() {
            console.log("价格属性被读取了!");
            // 返回值
            return 123;
        }
        // set里面要设置一个参数
        set price(value) {
            console.log("价格属性被修改了!");
        }
    }
    // 实例化对象
    let s = new Phone();
    console.log(s.price);
    // 返回值 
    s.price = 2999;
</script>

17.5 数值扩展

  • Number.EPSILON:Number.EPSILON 是 JavaScript 表示的最小精度;EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16;
  • 二进制和八进制:ES6 提供了二进制和八进制数值的新的写法,分别用前缀 0b 和 0o 表示;
  • Number.isFinite() 与 Number.isNaN() :Number.isFinite() 用来检查一个数值是否为有限的;Number.isNaN() 用来检查一个值是否为 NaN;
  • Number.parseInt() 与 Number.parseFloat():字符串转成整数,ES6 将全局方法 parseInt 和 parseFloat,移植到 Number 对象上面,使用不变;
  • Math.trunc:用于去除一个数的小数部分,返回整数部分
  • Number.isInteger:Number.isInteger() 用来判断一个数值是否为整数;
<script>
    // 数值扩展
    // 0. Number.EPSILON 是 JavaScript 表示的最小精度 
    // EPSILON 属性的值接近于 2.2204460492503130808472633361816E-16 
    // function equal(a, b){
    // return Math.abs(a-b) < Number.EPSILON; 
    // } 
    console.log("0、Number.EPSILON 是 JavaScript 表示的最小精度");
    // 箭头函数简化写法 equal = (a, b) => Math.abs(a-b) < Number.EPSILON; 
    console.log(0.1 + 0.2);
    console.log(0.1 + 0.2 === 0.3); // false 
    console.log(equal(0.1 + 0.2, 0.3)); // true
    // 1. 二进制和八进制 
    console.log("1、二进制和八进制");
    let b = 0b1010;
    let o = 0o777;
    let d = 100;
    let x = 0xff;
    console.log(x);
    // 2. Number.isFinite 检测一个数值是否为有限数
    console.log("2、Number.isFinite 检测一个数值是否为有限数");
    console.log(Number.isFinite(100));
    console.log(Number.isFinite(100 / 0));
    console.log(Number.isFinite(Infinity));
    // 3. Number.isNaN 检测一个数值是否为 NaN 
    console.log("3. Number.isNaN 检测一个数值是否为 NaN");
    console.log(Number.isNaN(123));
    // 4. Number.parseInt Number.parseFloat字符串转整数 
    console.log("4. Number.parseInt Number.parseFloat字符串转整数");
    console.log(Number.parseInt('5211314love'));
    console.log(Number.parseFloat('3.1415926神奇'));
    // 5. Number.isInteger 判断一个数是否为整数 
    console.log("5. Number.isInteger 判断一个数是否为整数");
    console.log(Number.isInteger(5));
    console.log(Number.isInteger(2.5));
    // 6. Math.trunc 将数字的小数部分抹掉 
    console.log("6. Math.trunc 将数字的小数部分抹掉 ");
    console.log(Math.trunc(3.5));
    // 7. Math.sign 判断一个数到底为正数 负数 还是零
    console.log("7. Math.sign 判断一个数到底为正数 负数 还是零");
    console.log(Math.sign(100));
    console.log(Math.sign(0));
    console.log(Math.sign(-20000));
</script>

17.6 对象方法扩展

ES6 新增了一些 Object 对象的方法:
  • Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与 NaN);
  • Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象; 
  • proto、setPrototypeOf、 setPrototypeOf 可以直接设置对象的原型;

18.模块化

(1)模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来;
(2)好处:
  • 防止命名冲突;
  • 代码复用;
  • 高维护性;
(3)模块化规范产品:
ES6 之前的模块化规范有:
  • CommonJS => NodeJS、Browserify;
  • AMD => requireJS;
  •  CMD => seaJS;
(4)ES6 模块化语法:模块功能主要由两个命令构成:export 和 import;
  • export 命令用于规定模块的对外接口(导出模块);
  • import 命令用于输入其他模块提供的功能(导入模块);

18.1暴露数据语法

17test.js(导出模块)
  • 分别暴露:在想要暴露的数据上export一下
export let school = "尚硅谷";
export function teach() {
    console.log("我们可以教你开发技术!");
}
  • 统一暴露
let school = "尚硅谷";
function teach() {
    console.log("我们可以教你开发技术!");
}
export { school, teach };
  • 默认暴露
export default {
    school: 'At',
    change: function() {
        console.log("我们可以改变你");
    }
}
在html文件中引入

<script type="module">
    import * as m1 from "./17test.js"; 
    console.log(m1);
    //默认暴露
    m1.default.change()
</script>

18.3引入数据语法

  • 通用导入形式
<script type="module">
    import * as m1 from "./17test.js"; 
    console.log(m1);
    //默认暴露
    m1.default.change()
</script>
  • 解构赋值形式
<script type="module">
    import { school, teach } from "./17test.js"; 
    //给school和teach设置了别名
    import { school as guigu, teach as fangfa } from "./17test.js";
    console.log(school);
    console.log(guigu);
</script>
  • 默认形式
<script type="module">
    // 要给default设置一个别名
    import { default as m3 } from "./17test.js"; 
    console.log(m3);
</script>
  • 简便形式 针对默认暴露
<script type="module">
    import  m3  from "./17test.js"; 
    console.log(m3);
</script>

18.4 使用模块化的另一种形式

  • 将原本写在html中的js整合到一个app.js文件中
import * as m from "./m.js"; 
console.log(m);
console.log(m.school);
m.teach();
  • 然后在html中执行js文件
<html>
<head>
    <meta charset="utf-8">
    <title>使用模块化的另一种方式</title>
</head>

<body>
    <script src="./js/app.js" type="module"></script>
</body>
</html>

19.原型和原型链

19.1 构造函数原型 prototype

构造函数通过原型分配的函数是所有对象所共享的。
JS规定,每一个构造函数都有一个prototype属性,指向另一个对象。prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法
<script>
    function Star(name, age) {
        this.name = name;
        this.age = age;
    }
    Star.prototype.sing = function() {
        console.log("我会唱歌");
    }
    var ldh = new Star("刘德华", 19);
    var zxy = new Star("张学友", 19);
    ldh.sing();
    zxy.sing();
</script>
  • 原型是什么?一个对象,我们也称prototype为一个原型对象
  • 原型作用?共享方法
  • 一般来说,我们的公共属性定义到构造函数里面
  • 公共方法放到原型对象身上,所以可以实现共享
  • 对象身上,系统自己添加一个__proto__,指向我们构造函数的原型对象prototype,__proto__对象原型和原型对象prototype是等价的。

19.2 构造函数

  • 对象原型(__ proto __)和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为他指向会构造函数本身。
  • constructor 主要用于记录该对象引用那个构造函数,它可以让原型对象重新指向原来的构造函数
  • 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,那么就必须手动利用constructor指回原来的函数
<script>
    function Star(name, age) {
        this.name = name;
        this.age = age;
    }
    Star.prototype = {
        // 如果有很多个所有对象所共享的方法,那么我们可以通过给Star的原型里面覆盖的方法进行编写函数
        // 但是把原来的构造函数覆盖掉
        // 所以我们要进行如下操作:constructer: Star,重新指回Star
        constructer: Star,
        sing: function() {
            console.log("我会唱歌");
        },
        movie: function() {
            console.log("我会演电影");
        }
    }
    var ldh = new Star("刘德华", 19);
    var zxy = new Star("张学友", 19);
    console.log(Star.prototype);
    console.log(ldh.__proto__);
    console.log(Star.prototype === ldh.__proto__); //true
</script>

19.3 三者之间的关系


19.4原型链


成员的查找规则:按照原型链进行查找
  • 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
  • 如果没有就查找它的原型(也就是__ proto __指向的prototype原型对象)。
  • 如果还没有就查找原型对象的原型(Object的原型对象)。
  • 以此类推一直找到Object为止(null)
  • __ proto __ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

19.5原型对象this指向

(1)类里面的 this指向问题
  • 在 ES 6 中类没有变量提升 所以必须先定义类 才能通过实例化对象
  • 类里面的共有的属性和方法一定要加this使用
  • constructor 【构造函数】里面的this指向实例对象 方法里面的this指向这个方法的调用者
<script>
    function Star(name, age) {
        this.name = name;
        this.age = age;
    }
    var that;
    Star.prototype.sing = function() {
        console.log("我会唱歌");
        that = this
    }
    var ldh = new Star("刘德华", 19);
    // 在构造函数中,里面的this指向的是对象实例ldh
    ldh.sing();
    console.log(that === ldh); //true
    // 原型对象函数里面的this指向实例对象 ldh
</script>

19.6扩展内置内向

可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给对象增加自定义求偶数和的功能。
(※)注意:数组和字符内置对象不能给原型对象覆盖操作 Array.prototype = {} , 只能是 Array.prototype.xxx = function(){}的方法。


19.7 call函数

ES6之前没有提供extends集成,所以我们可以通过构造函数+原型对象的方法模拟继承,被称为组合继承。
call():调用这个函数,并且修改函数运行时的this指向
<script>
    function fn(x, y) {
        console.log("1231213");
        console.log(this);
        console.log(x + y);
    }
    var o = {
        name: 'andy'
    };
    // fn();//可以调用函数
    //1.call可以调用函数
    // fn.call();
    //2. call可以改变函数this指向 此时这个函数this指向了o这个对象
    fn.call(o, 1, 2);
</script>

19.8 借用构造函数继承父类型属性

  • 核心原理:通过call() 把父类型的this 指向子类型的this , 这样就可以实现子类型继承父类型的属性。
  • 如果子构造函数调用父构造函数的话,一定要把父构造函数里面的this指向子构造函数里面的this
<script>
    function Father(name, age) {
        this.name = name;
        this.age = age;
    }

    function Son(name, age) {
        // this指向子构造函数的对象实例
        // 调用父亲构造函数,将父构造函数的this指向子构造函数
        Father.call(this, name, age);
    }
    var ldh = new Son("刘德华", 19);
    console.log(ldh);
</script>

19.9 借用构造函数继承父类型方法

<script>
    function Father(name, age) {
        this.name = name;
        this.age = age;
    }
    Father.prototype.money = function() {
        console.log(100);
    }

    function Son(name, age) {
        // this指向子构造函数的对象实例
        // 调用父亲构造函数,将父构造函数的this指向子构造函数
        Father.call(this, name, age);
    }
    // Son.prototype = Father.prototype; 这样赋值会有问题,如果直接修改了子原型对象,父原型对象也会改变
    // 所以我们要给Son.prototype覆盖一个新的对象Father,再在Father的基础上编辑子方法.这样怎么修改子原型对象都不会影响父原型对象了
    Son.prototype = new Father();
    // 子构造函数专门的方法
    Son.prototype.exam = function() {
        console.log("孩子要考试");
    }
    var ldh = new Son("刘德华", 19);
    console.log(ldh);
</script>

20.ES5 中新增的方法

迭(die)代(遍历)方法:forEach()、map()、filter()、 some()、every()
  • foreach()
var arr = [1, 2, 3];
arr.forEach(function(value, index, array) {
    console.log(value); //数组元素
    console.log(index); //元素索引号
    console.log(array); //数组本身
})
  • filter():创建一个新的数组,新数组中的元素时通过检查指定数组中符合条件的所有元素,主要用于筛选数组,注意它直接返回一个新数组
var arr = [12, 62, 43];
var newarr = arr.filter(function(value, index) {
    if (value >= 20)
        return true;
    else
        return false;
})
    console.log(newarr);
  • some():用于检测数组中的元素是否满足指定条件 通俗点 查找数组中是否有满足条件的元素,它返回值是布尔值,如果查找到这个元素,就返回true,如果查找不到就返回false
如果找到第一个满足条件的元素,则终止循环,不在继续查找
var arr = ['red', 'yellow', 'med'];
var flag = arr.some(function(value) {
    return value === 'red';
});
console.log(flag); //true
  • trim():会从一个字符串的两端删除空白字符
var str = '   andy   ';
var str1 = str.trim();
console.log(str);
console.log(str1);

21.闭包

  • 闭包(closure) 指有权访问另一个函数作用域中变量的函数。
  • 简单理解就是,一个作用域可以访问另外一个函数内部的局部变量,闭包本身就是一个函数
function fn() {
    var num = 10;

    function fun() {
        // fun可以使用fn
        console.log(num);
    }
    fun();
}

// vn外边的作用域也可以访问vn内部的局部变量
function vn() {
    var num = 10;

    // function vun() {
    //     console.log(num);
    // }
    // return vun;
    return function() {
        console.log(num);
    }
}
var v = vn();
// 类似于
// var f = function vun() {
//     console.log(num);
// }
// 外部可以使用vn内部变量num
v();
  1. 闭包是什么?
    闭包是一个函数(一个作用域可以访问另外一个函数的局部变量)
  2. 闭包的作用是什么?
    延伸变量的作用范围

21.1 闭包案例:点击li打印当前索引号

<body>
    <ul class="nav">
        <li>123</li>
        <li>546</li>
        <li>789</li>
        <li>498465</li>
    </ul>
    <script>
        var lis = document.querySelector(".nav").querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            // 以前做法:新建一个index
            // lis[i].index = i;
            // lis[i].onclick = function() {
            //     console.log(this.index);
            // }
            // 现在:利用闭包的方式得到当前li的索引号
            // 利用for循环,对每一个i先创建"立即执行函数",参数是下标i
            // 同时"立即执行函数"也成为了小闭包,因为立即执行函数黎曼任何一个函数都可以使用i这个变量
            (function(i) {
                lis[i].onclick = function() {
                    console.log(i);
                }
            })(i)
        }
    </script>
</body>

21.2 闭包案例:3s之后 打印所有li元素的内容

<body>
    <ul class="nav">
        <li>123</li>
        <li>546</li>
        <li>789</li>
        <li>498465</li>
    </ul>
    <script>
        var lis = document.querySelector(".nav").querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function(i) {
                setTimeout(function() {
                    console.log(lis[i].innerHTML);
                }, 3000);
            })(i);

        }
    </script>
</body>

21.3 闭包案例:计算打车价格

  • 3公里以内13元,之后每多1公里5元,用户输入公里数就可以计算打车价格
  • 如果拥堵 就额外收10元
<script>
    var car = (function() {
        var qibujia = 13;
        var zongjia = 0;
        return {
            price: function(n) {
                if (n <= 3) {
                    zongjia = qibujia;
                } else {
                    zongjia = qibujia + (n - 3) * 5;
                }
                return zongjia;
            },
            yongdu: function(flag) {
                return flag ? zongjia + 10 : zongjia;
            }
        }
    })();
    console.log(car.price(5));
    console.log(car.yongdu(true));
</script>

22.浅拷贝和深拷贝

  • 浅拷贝只是拷贝一层,更深层次对象级别的值拷贝引用,修改o里面的msg也会影响obj里面的msg

  • 深拷贝拷贝多层,每一级别的数据都会拷贝。
<script>
    var o = {};
    var obj = {
        nam: 13,
        age: 18,
        masg: {
            aggg: 18
        }
    };

    function deepCopy(newl, old) {
        for (var k in old) {
            // 判断属性值属于哪种数据类型
            // 1.获取属性值
            var item = old[k];
            // 2.判断是否是数组,数组写在Object上边 
            if (item instanceof Array) {
                newl[k] = [];
                deepCopy(newl[k], item);
            }
            // 3.判断是否是对象
            else if (item instanceof Object) {
                newl[k] = {};
                deepCopy(newl[k], item);
            }
            // 4.属于简单数据类型
            else {
                newl[k] = item;
            }
        }
    }
    deepCopy(o, obj);
    console.log(o);
</script>
  • Object.assign(target, …sources) ES6新增方法可以浅拷贝
var o = {};
var obj = {
    nam: 13,
    age: 18
    };
Object.assign(o, obj);

23.正则表达式

  • 概述:正则表达式(Regular Expression) 是用于匹配字符串中字符组合的模式。
  • 在 JavaScript中,正则表达式也是对象正则表通常被用来检索、替换那些符合某个模式(规则)的文本,列如验证表单:用户名表单只能输入英文字母、数字或下划线, 昵称输入框中可以输入中文(匹配)。
  • 此外,正则表达式还常用于过滤掉网页内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等。
  • 其他语言也会使用正则表达式,本阶段我主要是利用 JavaScript正则表达式完成表单验证
 

23.1 创建正则表达式

// 1RegEXP
var regexp=new RegExp(/123/);
console.log(regexp);
// 2字面量
var rg=/123/;

23.2检测正则表达式 test

test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false 其参数是测试字符串。

var rg = /123/;
console.log(rg.test(123)); //true
console.log(rg.test('abc')); //false

23.3正则表达式的特殊字符

  • 一个正则表达式可以由简单的字符构成,比如/abc/, 也可以是简单和特殊字符的组合,比如/ab*c/. 其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如^、$、+等
  • 特殊字符非常多,可以参考:
    • MDN
    • jQuery 手册
    • 正则测试工具
  • 边界符

// 边界符 以XX结尾$    以XX开头^
var rg = /abc/; //   /abc/表示只要这个字符串包含了abc这个字符串都是true
console.log(rg.test('abccccc')); //true
console.log(rg.test('abc')); //true
console.log(rg.test('bvbabc')); //true

var rg2 = /^abc/; //   /^abc/表示要以abc开头
console.log(rg2.test('abccccc')); //true
console.log(rg2.test('abc')); //true
console.log(rg2.test('bvbabc')); //false

var rg3 = /^abc$/; //   /^abc&/表示要以abc开头,以abc结尾,所以这个就是精确匹配必须是abc
console.log(rg3.test('abccccc')); //false
console.log(rg3.test('abc')); //true
console.log(rg3.test('abcabc')); //false

var rg4 = /abc$/; //   /^abc/表示要以abc结尾
console.log(rg4.test('abccccc')); //false
console.log(rg4.test('abc')); //true
console.log(rg4.test('bvbabc')); //true
  • 字符类[]
// 字符类:[]表示一系列字符可供选择 只要匹配其中一个就可以了
var rg = /[abc]/; //只要包含a 或者b 或者c都会返回true
console.log(rg.test('abc')); //true
console.log(rg.test('andy')); //true
console.log(rg.test('color')); //true
console.log(rg.test('mh')); //false

var rg2 = /^[abc]$/; //三选一 只有是a 或者 只有是b 或者 只有是c 这三个字母才返回true
console.log(rg2.test('a')); //true
console.log(rg2.test('aa')); //false
console.log(rg2.test('b')); //true
console.log(rg2.test('mh')); //false

var rg3 = /^[a-z]$/; //[-]26个英文字母任何一个字母都会返回true
console.log(rg3.test('z')); //true
console.log(rg3.test('Z')); //false 大写也不行
  • 字符组合
// 字符组合
var rg4 = /^[a-zA-Z0-9_]$/; //限制用户只能输入英文字母和数字和下划线
console.log(rg4.test('_')); //true
  • 在[]里面的^表示取反
var rg5 = /^[^a-zA-Z0-9_]$/; //用户不能输入英文字母和数字和下划线
console.log(rg5.test('_')); //false
  • 量词符

// *:代表大于等于0 可以出现0次或者很多次
var re = /^a*$/;
console.log(re.test('')); //true
console.log(re.test('aaa')); //true
console.log(re.test('a')); //true

// +:代表大于等于1 可以出现1次或者很多次
var re1 = /^a+$/;
console.log(re1.test('')); //false
console.log(re1.test('aaa')); //true
console.log(re1.test('a')); //true

//?:代表  1||0  只有出现一次或者一次都不出现才对
var re2 = /^a?$/;
console.log(re2.test('')); //true
console.log(re2.test('aaa')); //fasle
console.log(re2.test('a')); //true

//{3}:代表重复三次
var re3 = /^a{3}$/;
console.log(re3.test('')); //false
console.log(re3.test('aaa')); //true
console.log(re3.test('a')); //false

//{3,}:代表重复大于等于三次
var re4 = /^a{3,}$/;
console.log(re4.test('')); //false
console.log(re4.test('aaa')); //true
console.log(re4.test('aaaaaa')); //true
console.log(re4.test('a')); //false

//{3,8}:代表重复大于等于三次,小于等于8次
var re5 = /^a{3,}$/;
console.log(re5.test('')); //false
console.log(re5.test('aaaa')); //true
console.log(re5.test('aaaaaaaaaaaaaaaaaaa')); //false
console.log(re5.test('a')); //false
//循环次数之间不能有空格
var rg4 = /^[a-zA-Z0-9_]{6,16}$/;
  • 括号总结
(1)大括号 量词符:里面表示重复次数
(2)中括号 字符集合。匹配方括号中的任意字符
(3)小括号 表示优先级
// 让c重复6次
var rg4 = /^abc{6}$/;
// 让abc重复6次
var rg4 = /^(abc){6}$/;
  • 在线测试工具
https://c.runoob.com/

23.4正则表达式预定义类


// 座机验证:010-12345678 或者(|) 0535-1234567
var regg=/^\d{3}-\d{8} | \d{4}-\d{7}$/;

24.5 正则替换,用于敏感词替换

  • replace 替换:replace() 方法可以实现替换字符串的操作,用来替换的参数可以是一个字符串或者一个正则表达式。


stringObject.replace(regexp/substr,replacement)


  1. 第一个参数:被替换的字符串 或者 正则表达式
  2. 第二个参数:替换的字符串
  3. 返回值是一个替换完毕的新字符串



  • 正则表达式参数


/表达式/[switch]
switch (也称为修饰符) 按照什么样的模式来匹配,有三种值:


  • g【global】 : 全局匹配
  • i 【ignore】: 忽略大小写
  • gi : 全局匹配+忽略大小写





全部评论

相关推荐

评论
2
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务