ES2015(ES6)新特性

ES6教程 | 菜鸟教程

🔱let变量声明及其特性

  • 变量不能重复声明
    错误示例:
let star = '罗志祥'
let star = '小猪'
  • 块级作用域(全局、函数、eval)
    错误示例:
if else while for
{
	let girl = '周扬青'
}
console.log(girl)
  • 不存在变量提升
    错误示例:
console.log(song)
let song = '恋爱达人'
  • 不影响作用域链
{
    let school = '尚硅谷'
    function fn() {
        console.log(school)
    }
    fn()
}
  • let实践案例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>点击 DIV 换色</title>
    <link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
        rel="stylesheet">
    <style>
        .item {
            width: 100px;
            height: 50px;
            border: solid 1px rgb(42, 156, 156);
            float: left;
            margin-right: 10px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h2 class="page-header">点击切换颜色</h2>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <script>
        //获取div元素对象
        let items = document.getElementsByClassName('item');

        //遍历并绑定事件
        for (let i = 0; i < items.length; i++) {
            items[i].onclick = function () {
                //修改当前元素的背景颜色
                //this.style.background = 'pink';
                items[i].style.background = 'pink';
            }
        }

    </script>
</body>

</html>

🔱const常量声明及其特性

  • 声明时一定要赋初值
  • 一般常量使用大写(潜规则)
  • 常量的值不能修改
  • 块级作用域
  • 对于 数组和对象 的元素的修改,不算作对常量的修改,不会报错

🔱变量的解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。

数组的解构:

const F4 = ['小沈阳', '刘能', '赵四', '宋小宝'];
let [xiao, liu, zhao, song] = F4;
console.log(xiao);
console.log(liu);
console.log(zhao);
console.log(song);

对象的解构:

const zhao = {
    name: '赵本山',
    age: '不详',
    xiaopin: function () {
        console.log("我可以演小品");
    }
};

let { name, age, xiaopin } = zhao;
console.log(name);
console.log(age);
console.log(xiaopin);
xiaopin();

// let { xiaopin } = zhao;
// xiaopin();

🔱模板字符串

ES6引入新的声明字符串的方式『``』。

  • 声明
let str = `我也是一个字符串哦!`;
console.log(str, typeof str);
  • 内容中可以直接出现换行符
let str = `<ul>
            <li>沈腾</li>
            <li>玛丽</li>
            <li>魏翔</li>
            <li>艾伦</li>
            </ul>`;
  • 变量拼接
let lovest = '魏翔';
let out = `${lovest}是我心目中最搞笑的演员!!`;
console.log(out);

🔱对象属性的简写形式

ES6允许在大括号里面直接写入变量和函数,作为对象的属性和方法。

let name = '尚硅谷';
let change = function () {
    console.log('我们可以改变你!!');
};

const school = {
    name,
    change,
    improve() {
        console.log("我们可以提高你的技能");
    }
};

console.log(school);

🔱箭头函数声明及其特性

ES6允许使用『箭头』=>定义函数。

  • 声明一个函数
let fn = (a, b) => {
    return a + b;
};
  • 调用函数
let result = fn(1, 2);
console.log(result);

特性:

  • this是静态的,this始终指向函数声明时所在作用域下的this的值
function getName() {
    console.log(this.name);
}
let getName2 = () => {
    console.log(this.name);
};

//设置 window 对象的 name 属性
window.name = '尚硅谷';
const school = {
    name: "ATGUIGU"
};

//直接调用
getName(); // 尚硅谷
getName2(); // 尚硅谷

//call 方法调用
getName.call(school); // ATGUIGU
getName2.call(school); // 尚硅谷
  • 不能作为构造函数去实例化对象
let Person = (name, age) => {
    this.name = name;
    this.age = age;
};
let me = new Person('xiao', 30); // 报错❌❌❌
  • 不能使用arguments变量
let fn = () => {
    console.log(arguments); // 报错❌❌❌
};
fn(1, 2, 3);
  • 箭头函数的简写:当形参有且只有一个的时候可以省略小括号
let add = n => {
    return n + n;
};
console.log(add(9));
  • 箭头函数的简写:当代码块只有一条语句时可以省略花括号(此时return也必须省略),这一条语句的执行结果就是函数的返回值
let pow = n => n * n;
console.log(pow(8));

案例一:点击 div 2秒后颜色变成粉色

// 获取元素
let ad = document.getElementById('ad');
// 绑定事件
ad.addEventListener("click", function () {
    // 保存 this 的值
    // let _this = this;
    // 定时器
    setTimeout(() => {
        console.log(this);
        // 修改背景颜色 this
        // _this.style.background = 'pink';
        this.style.background = 'pink';
    }, 2000);
});

案例二:从数组中返回偶数的元素

const arr = [1, 6, 9, 10, 100, 25];

// 方法1
const result = arr.filter(function (item) {
    if (item % 2 === 0) {
        return true;
    } else {
        return false;
    }
});

// 方法2
const result = arr.filter(item => item % 2 === 0);

console.log(result);

小总结:
箭头函数适合与this无关的回调,如:定时器、数组的方法回调。
箭头函数不适合与this有关的回调,如:事件的回调、对象的方法。

🔱函数形参的默认值设置

ES6允许给函数参数赋初始值。

  • 形参具有默认值的参数,一般位置要靠后(潜规则)
    错误示例:
function add(a, c = 10, b) {
    return a + b + c;
}
let result = add(1, 2);
console.log(result); // NaN
  • 与解构赋值结合使用
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
})

🔱函数形参的rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments

  • 回顾ES5获取实参的方式
function date() {
    console.log(arguments); // arguments是对象
}
date('白芷', '阿娇', '思慧');
  • ES6中函数的rest参数
function date(...args) {
    console.log(args); // args是数组
}
date('阿娇', '柏芝', '思慧');
  • :形参有多个且有rest参数时,rest参数必须放在最后
function fn(a, b, ...args) {
    console.log(a);
    console.log(b);
    console.log(args);
}
fn(1, 2, 3, 4, 5, 6);

🔱扩展运算符〔…〕

扩展运算符能将『数组』转换为逗号分隔的『参数序列』。

const tfboys = ['易烊千玺', '王源', '王俊凯'];

function chunwan() {
    console.log(arguments);
}

chunwan(...tfboys);
// 相当于
chunwan('易烊千玺', '王源', '王俊凯');

扩展运算符的应用:

  1. 数组的合并:
const kuaizi = ['王太利', '肖央'];
const fenghuang = ['曾毅', '玲花'];
// const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
console.log(zuixuanxiaopingguo);
  1. 数组的克隆:
const sanzhihua = ['E', 'G', 'M'];
const sanyecao = [...sanzhihua]; // ['E', 'G', 'M']
console.log(sanyecao);
  1. 将伪数组转为真正的数组:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div></div>
    <div></div>
    <div></div>
    <script>
        const divs = document.querySelectorAll('div');
        const divArr = [...divs];
        console.log(divs);
        console.log(divArr);
    </script>
</body>

</html>

结果:
扩展运算符

🔱一个新的数据类型〔Symbol〕

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol的特点:
①Symbol的值是唯一的,用来解决命名冲突的问题。
②Symbol值不能与其他数据进行运算。
③Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。

:遇到唯一性的场景时要想到Symbol

  • 创建Symbol
// 创建Symbol
let s = Symbol();
console.log(s, typeof s); // Symbol() 'symbol'
let s2 = Symbol('尚硅谷');
let s3 = Symbol('尚硅谷');
console.log(s2 === s3); // false

// Symbol.for 创建
/*
Symbol.for() 类似单例模式,
首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,
如果有即返回该 Symbol 值,
若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
*/
let s4 = Symbol.for('尚硅谷');
let s5 = Symbol.for('尚硅谷');
console.log(s4 === s5); // true

// 不能与其他数据进行运算,以下全都报错❌❌❌
// let result = s + 100;
// let result = s > 100;
// let result = s + s;
  • 对象添加Symbol类型的属性

由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。

// 向对象中添加方法 up down
let game = {
  name: '俄罗斯方块',
  up: function () { },
  down: function () { }
}

// 声明一个对象
let methods = {
  up: Symbol(),
  down: Symbol()
}

// 不确定game对象有没有up或down方法,但是我们想要给game对象添加up和down的功能
game[methods.up] = function () {
  console.log("我可以改变形状")
}

game[methods.down] = function () {
  console.log("我可以快速下降")
}

game[methods.up]() // 我可以改变形状
game[methods.down]() // 我可以快速下降
console.log(game)

let youxi = {
  name: "狼人杀",
  [Symbol('say')]: function () {
    console.log("我可以发言")
  },
  [Symbol('zibao')]: function () {
    console.log('我可以自爆')
  }
}

// 这里不能调用youxi的方法,因为那两个方法没有事先用变量名保存
console.log(youxi)
  • Symbol内置属性

除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法,可以称这些方法为魔术方法,因为它们会在特定的场景下自动执行。
Symbol内置属性

class Person {
    static [Symbol.hasInstance](param) {
        console.log(param);
        console.log("我被用来检测类型了");
        return false;
    }
}

let o = { a: 1, b: 2 };

console.log(o instanceof Person); // false

const arr = [1, 2, 3];
const arr2 = [4, 5, 6];
arr2[Symbol.isConcatSpreadable] = false;
console.log(arr.concat(arr2));

结果:
Symbol内置属性

🔱迭代器〔for…of〕

------迭代器(iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。
------ES6创造了一种新的遍历命令for...of循环,iterator接口主要供for...of消费。
------原生具备iterator接口的数据(可用for...of遍历):ArrayArgumentsSetMapStringTypedArrayNodeList

// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];

// 使用 for...in 遍历数组
for (let v in xiyou) {
    console.log(v);
}

// 使用 for...of 遍历数组
for (let v of xiyou) {
    console.log(v);
}

// 调用xiyou的Symbol.iterator方法,获取方法返回的对象,这个对象有next方法
let iterator = xiyou[Symbol.iterator]();

// 调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

结果:
iterator

工作原理:

  1. 创建一个指针对象,指向当前数据结构的起始位置。
  2. 第一次调用对象的next方法,指针自动指向数据结构的第一个成员。
  3. 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员。
  4. 每次调用next方法返回一个包含valuedone属性的对象。

:需要自定义遍历数据的时候,要想到迭代器。

迭代器自定义遍历对象:

//声明一个对象
const banji = {
    name: "终极一班",
    stus: [
        'xiaoming',
        'xiaoning',
        'xiaotian',
        'knight'
    ],
    [Symbol.iterator]() {
        //索引变量
        let index = 0;
        let _this = this;
        return {
            next: function () {
                if (index < _this.stus.length) {
                    const result = { value: _this.stus[index], done: false };
                    //下标自增
                    index++;
                    //返回结果
                    return result;
                } else
                    return { value: undefined, done: true };
            }
        };
    }
};

//遍历这个对象 
for (let v of banji) {
    console.log(v);
}

结果:
迭代器自定义遍历对象

🔱生成器函数

生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。

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());

console.log('--------------------------------------------------');
for (let v of gen()) {
  console.log(v);
}

结果:
生成器函数

function* gen(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 iterator = gen('AAA');
console.log(iterator.next());
//next方法可以传入实参
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));

结果:
生成器函数

代码说明:

  • 生成器函数返回的结果是迭代器对象,调用迭代器对象的next方法可以得到yield语句后的值。
  • yield相当于函数的暂停标记,也可以认为是函数的分隔符,每调用一次next方法就会执行一段代码。
  • next方法可以传递实参,作为函数中当前执行代码段开始处的yield语句的返回值。

案例一: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()
    }, 1000)
}

function two() {
    setTimeout(() => {
        console.log(222)
        iterator.next()
    }, 2000)
}

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

function* gen() {
    yield one()
    yield two()
    yield three()
}

//调用生成器函数
let iterator = gen()
iterator.next()

案例二:模拟获取:用户数据,订单数据,商品数据

function getUsers() {
    setTimeout(() => {
        let data = '用户数据'
        //调用 next 方法, 并且将数据传入
        iterator.next(data)
    }, 1000)
}

function getOrders() {
    setTimeout(() => {
        let data = '订单数据'
        iterator.next(data)
    }, 1000)
}

function getGoods() {
    setTimeout(() => {
        let data = '商品数据'
        iterator.next(data)
    }, 1000)
}

function* gen() {
    let users = yield getUsers()
    console.log(users)
    let orders = yield getOrders()
    console.log(orders)
    let goods = yield getGoods()
    console.log(goods)
}

//调用生成器函数
let iterator = gen()
iterator.next()

结果:
生成器函数

🔱Promise对象

Promise是ES6引入的异步编程的新的解决方案。语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
Promise 状态的特点:
------Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。
------Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

  • Promise基本语法
// 实例化 Promise 对象
const p = new Promise(function (resolve, reject) {
    setTimeout(function () {
        // let data = '数据库中的用户数据'
        // resolve(data)

        let err = '数据读取失败'
        reject(err)
    }, 1000)
})

// 调用 Promise 对象的 then 方法
p.then(function (value) {
    console.log(value)
}, function (reason) {
    console.error(reason)
})
  • Promise封装读取文件(node运行环境)
//1. 引入 fs 模块
const fs = require('fs')

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

//3. 使用 Promise 封装
const p = new Promise(function (resolve, reject) {
    fs.readFile("./resources/为学.mda", (err, data) => {
        //判断如果失败
        if (err) reject(err)
        //如果成功
        resolve(data)
    })
})

p.then(function (value) {
    console.log(value.toString())
}, function (reason) {
    console.log("读取失败!")
})
  • Promise封装Ajax
//接口地址: https://api.apiopen.top/getJoke
const p = new Promise((resolve, reject) => {
    //1. 创建对象
    const xhr = new XMLHttpRequest()

    //2. 初始化
    xhr.open("GET", "https://api.apiopen.top/getJ")

    //3. 发送
    xhr.send()

    //4. 绑定事件, 处理响应结果
    xhr.onreadystatechange = function () {
        //判断
        if (xhr.readyState === 4) {
            //判断响应状态码 200-299
            if (xhr.status >= 200 && xhr.status < 300) {
                //表示成功
                resolve(xhr.response)
            } else {
                //如果失败
                reject(xhr.status)
            }
        }
    }
})

//指定回调
p.then(function (value) {
    console.log(value)
}, function (reason) {
    console.error(reason)
})
  • then 方法
    then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。
//创建 Promise 对象
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('用户数据')
        reject('出错啦')
    }, 1000)
})

//调用 then 方法, then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
//如果回调函数中返回的结果是 非Promise 类型的属性, 状态为成功, 返回值为对象的成功的值

const result = p.then(value => {
    console.log(value)
    //1. 非 Promise 类型的属性
    return 'iloveyou'
    //2. 是 Promise 对象
    return new Promise((resolve, reject) => {
        resolve('ok')
        reject('error')
    })
    //3. 抛出错误
    throw '出错啦!'
    //4. 不返回任何值则是undefined, 状态也是成功
}, reason => {
    console.warn(reason)
})
console.log(result) // result也是Promise对象
  • catch 方法
    简单的语法糖,可以用 then 方法替代
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        // 设置 p 对象的状态为失败, 并设置失败的值
        reject("出错啦!")
    }, 1000)
})

// 方式一:
p.then(function (value) { }, function (reason) {
    console.error(reason) // 出错啦!
})

// 方式二:
p.catch(function (reason) {
    console.warn(reason) // 出错啦!
})

链式调用:

//创建 Promise 对象
const p = new Promise((resolve, reject) => {
  resolve('用户数据')
})

//链式调用
const result =
  p
    .then(value => {
      console.log('value1:', value)
      return new Promise(function (resolve, reject) {
        reject('出错啦')
      })
    }, reason => {
      console.log('reason1:', reason)
    })

    .then(value => {
      console.log('value2:', value)
    }, reason => {
      console.log('reason2:', reason)
    })

console.log('打印result:', result)

结果:
promise链式调用

  • Promise实践------读取多个文件(node运行环境)
// 引入 fs 模块
const fs = require("fs")

// 回调地狱实现
fs.readFile('./resources/为学.md', (err, data1) => {
    fs.readFile('./resources/插秧诗.md', (err, data2) => {
        fs.readFile('./resources/观书有感.md', (err, data3) => {
            let result = data1 + '\r\n' + data2 + '\r\n' + data3
            console.log(result)
        })
    })
})

// 使用 Promise 实现
new Promise((resolve, reject) => {
    fs.readFile("./resources/为学.md", (err, data) => {
        resolve(data)
    })
})
    .then(value => {
        return new Promise((resolve, reject) => {
            fs.readFile("./resources/插秧诗.md", (err, data) => {
                resolve([value, data])
            })
        })
    })
    .then(value => {
        return new Promise((resolve, reject) => {
            fs.readFile("./resources/观书有感.md", (err, data) => {
                //压入
                value.push(data)
                resolve(value)
            })
        })
    })
    .then(value => {
        console.log(value.join('\r\n'))
    })

🔱Set(集合)对象

ES6提供了新的数据结构Set(集合),它类似于数组,但成员的值都是唯一的。集合实现了iterator接口,所以可以使用〔扩展运算符...〕和〔for...of〕进行遍历。

// 声明一个 set
let s = new Set()
console.log(typeof s)

let s2 = new Set(['大事儿', '小事儿', '好事儿', '坏事儿', '小事儿'])
console.log(s2)
for (let v of s2) {
    console.log(v)
}

// 元素个数
console.log(s2.size)

// 添加新的元素
s2.add('喜事儿')
console.log(s2)

// 删除元素
s2.delete('坏事儿')
console.log(s2)

// 检测
console.log(s2.has('糟心事'))

// 清空
s2.clear()
console.log(s2)

结果:
集合Set
Set 实践:

  1. 数组去重:
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let result = [...new Set(arr)]

console.log(result)
// (5) [1, 2, 3, 4, 5]
  1. 交集:
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)
  if (s2.has(item))
    return true
  else
    return false
}) */

// 方法二
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))

console.log(result)
// (2) [4, 5]
  1. 并集:
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]
let arr2 = [4, 5, 6, 5, 6]

let union = [...new Set([...arr, ...arr2])]
console.log(union)
// (6) [1, 2, 3, 4, 5, 6]
  1. 差集:
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)
// (3) [1, 2, 3]

🔱Map对象

ES6提供了Map数据结构,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作“键”。Map也实现了iterator接口,所以可以使用〔扩展运算符...〕和〔for...of〕进行遍历。

// 声明 Map
let m = new Map()

// 添加元素
m.set('name', '尚硅谷')
m.set('change', function () {
    console.log("我们可以改变你!")
})
let key = {
    school: 'ATGUIGU'
}
m.set(key, ['北京', '上海', '深圳'])
console.log(m)

// 遍历
for (let v of m) {
    console.log(v)
}

// size
console.log(m.size)

// 删除
m.delete('name')
console.log(m)

// 获取
console.log(m.get('change'))
console.log(m.get(key))

// 清空
m.clear()
console.log(m)

结果:
ES6Map

🔱class类

ES6提供了更接近传统语言的写法,引入了class(类)这个概念,作为对象的模板。通过class关键字可以定义类。基本上,ES6的class可以看作只是一个语法糖(class 的本质是 function),它的绝大部分功能ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

  • class声明类
    constructor定义构造函数初始化
//ES5
function Phone(brand, price) {
    this.brand = brand
    this.price = price
}

//添加方法
Phone.prototype.call = function () {
    console.log("我可以打电话!!")
}

//实例化对象
let Huawei = new Phone('华为', 5999)
Huawei.call()
console.log(Huawei)



//ES6 class
class Shouji {
    //构造方法 名字不能修改
    constructor(brand, price) {
        this.brand = brand
        this.price = price
    }

    //方法必须使用该语法, 不能使用 ES5 的对象完整形式
    call() {
        console.log("我可以打电话!!")
    }
}

let onePlus = new Shouji("1+", 1999)
console.log(onePlus)

结果:
class类声明

  • static定义静态属性和方法
    static定义的属性和方法是构造函数对象的属性和方法,其实例化对象不能共享
class Phone {
    // 静态属性中不能有name属性, 因为name属性的值是'Phone', 已经自带了, 且不可改变
    static shouji = '手机'
    static change() {
        console.log("我可以改变世界")
    }
}
console.dir(Phone)

let nokia = new Phone()
console.log(nokia.shouji) // undefined
console.log(nokia.change) // undefined

console.log(Phone.shouji) // 手机
Phone.change() // 我可以改变世界
  • 回顾ES5的原型链继承模式之组合继承
//手机
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.playGame = function () {
    console.log("我可以玩游戏")
}

const chuizi = new SmartPhone('锤子', 2499, '黑色', '5.5inch')

console.log(chuizi)

结果:
ES5组合继承

  • ES6实现类继承
class Phone {
  // 构造方法
  constructor(brand, price) {
    this.brand = brand
    this.price = price
  }

  // 父类的成员属性
  call() {
    console.log('我可以打电话')
  }
}

// 通过 extends 实现类的继承
class SmartPhone extends Phone {
  constructor(brand, price, color, size) {
    // 子类 constructor 方法中必须有 super , 且必须出现在 this 之前
    // super 调用父类构造函数
    super(brand, price) // 相当于Phone.call(this, brand, price)
    this.color = color
    this.size = size
  }

  photo() {
    console.log('我可以拍照')
  }

  game() {
    console.log('我可以玩游戏')
  }

  // 重写父类的call方法
  call() {
  // super.call() // 弹幕网友说这样可以调父类的call方法, 试了确实可以
  // 调用父类方法, super作为对象, 在普通方法中, 指向父类的原型对象, 在静态方法中, 指向父类
  // 这里是在普通方法中使用super, 所以super就是父类的原型对象, 也就是调用父类原型对象上的call方法
  // 以上三行注释都是讲的'super.call()'这句代码
    console.log('我可以进行视频通话')
  }
}

let xiaomi = new SmartPhone('小米', 1999, '黑色', 5.5)
console.log(xiaomi)
xiaomi.photo()
xiaomi.game()
xiaomi.call()

let dageda = new Phone('大哥大', 999)
console.log(dageda)
dageda.call()

结果:
ES6实现类继承

  • get 和 set 属性
class Example {
  constructor(a, b) {
    this.a = a // 实例化时调用set方法
    this.b = b
  }
  get a() {
    console.log('getter被调用了')
    return this.c
  }
  set a(newValue) { // 括号里的值为修改后的值
    console.log('setter被调用了')
    this.c = newValue
  }
}
let exam = new Example(5, 10)
// 上一行代码执行完后输出'setter被调用了', 此时exam有三个属性{b: 10, c: 5, a: (...)}

console.log(exam)
// 上一行代码执行完后输出exam对象

console.log(exam.a)
// 上一行代码执行完后输出'getter被调用了', 然后又输出'5'(这是c的'5')

console.log(exam.c)
// 上一行代码执行完后输出c, 值为'5'

exam.a = 20
// 上一行代码执行完后输出'setter被调用了', 修改的不是a, 而是c, 修改c值为'20'

console.log(exam.c)
// 上一行代码执行完后输出c, 值为'20'

🔱数值的扩展

// Number.EPSILON 是 JavaScript 表示的最小精度
function equal(a, b) {
    if (Math.abs(a - b) < Number.EPSILON)
        return true
    else
        return false
}
console.log(0.1 + 0.2 === 0.3) // false
console.log(equal(0.1 + 0.2, 0.3)) // true


// 二进制和八进制
let b = 0b1010
let o = 0o777
console.log(b) // 10
console.log(o) // 511

let d = 100
let x = 0xff
console.log(d) // 100
console.log(x) // 255


// Number.isFinite 检测一个数值是否为有限数
console.log(Number.isFinite(100)) // true
console.log(Number.isFinite(100 / 0)) // false
console.log(Number.isFinite(Infinity)) // false


// Number.isNaN 检测一个数值是否为 NaN
console.log(Number.isNaN(123)) // false


// Number.parseInt   Number.parseFloat   字符串转整数
console.log(Number.parseInt('5211314love')) // 5211314
console.log(Number.parseFloat('3.1415926神奇')) // 3.1415926


// Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(5)) // true
console.log(Number.isInteger(2.5)) // false


// Math.trunc 将数字的小数部分抹掉
console.log(Math.trunc(3.5)) // 3


// Math.sign 判断一个数到底为正数、负数还是零
console.log(Math.sign(100)) // 1
console.log(Math.sign(0)) // 0
console.log(Math.sign(-20000)) // -1

🔱对象的扩展

// Object.is 判断两个值是否完全相等
console.log(Object.is(120, 120)) // true
console.log(Object.is(NaN, NaN)) // true
console.log(NaN === NaN) // false


// Object.assign 对象的合并
const config1 = {
    host: 'localhost',
    port: 3306,
    name: 'root',
    pass: 'root',
    test: 'test'
}
const config2 = {
    host: 'http://atguigu.com',
    port: 33060,
    name: 'atguigu.com',
    pass: 'iloveyou',
    test2: 'test2'
}
console.log(Object.assign(config1, config2))
/*
{host: "http://atguigu.com"
name: "atguigu.com"
pass: "iloveyou"
port: 33060
test: "test"
test2: "test2"}
*/


// Object.setPrototypeOf 设置原型对象
// Object.getPrototypeof 获取原型对象
const school = {
    name: '尚硅谷'
}
const cities = {
    xiaoqu: ['北京', '上海', '深圳']
}
Object.setPrototypeOf(school, cities)
console.log(Object.getPrototypeOf(school)) // {xiaoqu: Array(3)}
console.log(school) // {name: '尚硅谷'}

🔱模块化

m1.js(分别暴露):

export let school = '尚硅谷'

export function teach() {
    console.log("我们可以教给你开发技能")
}

m2.js(统一暴露):

let school = '尚硅谷'

function findJob() {
    console.log("我们可以帮助你找工作")
}

export { school, findJob }

m3.js(默认暴露):

export default {
    school: 'ATGUIGU',
    change: function () {
        console.log("我们可以改变你")
    }
}
  • 方式一,直接在主html文件里面导入模块

index.html:

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script type="module">
    /* 通用的导入方式 */
    import * as m1 from "./src/js/m1.js"
    console.log(m1)

    import * as m2 from "./src/js/m2.js"
    console.log(m2)

    import * as m3 from "./src/js/m3.js"
    console.log(m3)



    /* 解构赋值形式 */
    import { school, teach } from "./src/js/m1.js"
    console.log(school)
    teach()

    // guigu是school的别名
    import { school as guigu, findJob } from "./src/js/m2.js"
    console.log(guigu)
    findJob()

    import { default as m33 } from "./src/js/m3.js"
    console.log(m33.school)
    m33.change()



    /* 简便形式, 只针对默认暴露 */
    import m333 from "./src/js/m3.js"
    console.log(m333.school)
    m333.change()
</script>

</html>

结果:
ES6模块化

  • 方式二,在主html文件中只引入一个js文件叫app.js,这个js文件用来管理所有模块

app.js:

/* 入口文件 */

import * as m1 from "./m1.js"
import * as m2 from "./m2.js"
import * as m3 from "./m3.js"

m1.teach()
m2.findJob()
m3.default.change()

/* 结果:
我们可以教给你开发技能
我们可以帮助你找工作
我们可以改变你
*/

index.html:

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

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

</html>
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值