一、简介
js由三部分组成:ES+DOM
(文档对象模型)+ BOM
(浏览器对象模型)
ES作为核心,是一套标准,规范了语言的组成部分:语法、类型、语句、关键字、保留字。定义了数据结构和语法,定义了函数和对象的实现,包括原型链和作用域链的机制和实现。
JavaScript
的核心 ECMAScript
描述了该语言的语法和基本对象;
DOM
描述了处理网页内容的方法和接口;
BOM
描述了与浏览器进行交互的方法和接口;
关于ES6详细的介绍请查看:《ECMAScript 6标准入门》
二、let使用说明
let
是 ES6
新引入的声明变量的方式,特点:
- 不能重复声明
let star = '123';
let star = '123';//Identifier 'star' has already been declared
-
块级作用域,仅在代码块内生效。
var
是全局作用域 -
不存在变量提升
console.log(name);
let name = '世界你好';// Cannot access 'name' before initialization
三、const使用说明
const
相当于常量
1.一定要赋初始值
const A = 1
- 一般常量要大写
const A = 100;
console.log(A)
3.常量的值不能修改
A = 200//Assignment to constant variable.
4.const也是块级作用域
{
const PLAYER = '李四';
}
console.log(PLAYER);//PLAYER is not defined
5.对数组和对象的对象修改,不算对常量的修改,不会报错,建议用 const
声明数组和对象
const FOOL = ['苹果','西瓜','水蜜桃','李子'];
FOOL.push('草莓');
console.log(FOOL);
四、变量的解析赋值
ES6允许按照一定的模式从数组或对象中提取值,对变量进行赋值,称之为变量的解析赋值
1.数组的结构
const F4 = ['刘能','赵四','小沈阳','宋小宝'];
let [liu,zhao,xiao,song] = F4;
console.log(liu);
console.log(zhao);
console.log(xiao);
console.log(song);
2.对象的结构
const Person = {
name: '张三',
age: 12,
learn: function(){
console.log('努力学习,找到好工作');
}
}
let {name, age, learn} = Person;
console.log(name);
console.log(age);
console.log(learn);
learn();
六、简化对象写法
ES6允许在大括号里,直接写入变量和函数,作为对象的属性和方法。
let name = '张三';
let learn = function(){
console.log('张三在学习');
}
const person = {
name,
learn,
dosometing(){
console.log('做点什么比较好');
}
}
console.log(person);
person.dosometing();
person.learn();
七、箭头函数的使用
ES6允许使用箭头 =>
定义函数
- 箭头函数适合与this无关的回调,定时器,数组方法回调
- 不适合与this有关的回调。事件回调,对象的方法
原始函数的声明:
let fn = function (a,b){
xxxxxx
return xxx;
}
使用箭头函数声明:
let fn = (a,b) =>{
return a + b;
}
// 函数调用
let result = fn(3,3)
console.log(result)
使用规范:
this
是静态的。this始终指向函数声明时所在作用域下的this
的值
function getName(){
console.log(this.name);
}
let getName2 = ()=>{
console.log(this.name);
}
window.name = 'hello ES6';
const dog = {
name: "你好"
}
//直接调用
getName();
getName2();
//call方法调用
getName.call(dog);
getName2.call(dog);
- 不能作为构造函数实例化对象
let person = (name,age) => {
this.name = name;
this.age = age;
}
let someone = new person('zhangsan',12);
console.log(someone);//Uncaught TypeError: person is not a constructor
- 不能使用
argument
变量
let fn = () =>{
console.log(arguments);
}
fn(1,2,3);
- 箭头函数简写
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 | //1)省略小括号,当形参只有一个的时候
let
add = n => {
``return
n+n;
}
console.log(add(10))
//2)省略花括号,当代码只有一条执行语句时,此时return必须省略,而且语句的执行结果就是返回值
let
pow = n => n*n
console.log(pow(12))
|
八、函数参数默认值
ES6允许函数参数赋值初始值
- 形参初始值 具有默认值的参数,一般位置靠后(约定俗成)
function add (a,b,c=10){
return a + b + c;
}
let result =add(1,2)
console.log(result)
- 与解构赋值结合,也可以进行初始化赋值
function connect ({host = '127.0.0.1',username,password,port}){
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
connect({
// host:'localhost',
username:'root',
password:'root',
port:3306
})
九、rest参数
ES6引入 rest
参数,用于获取函数的实参,用来代替argument
- ES5获取实参的方式
function data (){
console.log(arguments)//arguments是一个对象
}
data('dog','cat','pig')
- ES6的
rest
参数,是一个数组,可以使用数组相关的api如:filter
some
every
map
等
function data (...args){
console.log(args)
}
data('dog','cat','pig')
rest
参数必须放到参数最后
function data (...args){
console.log(args)
}
data('dog','cat','pig')
十、spread扩展运算符
...
扩展运算符能将【数组】转化为逗号分隔的【参数序列】
声明数组
const F4 = ['刘能','赵四','小沈阳','宋小宝'];
声明函数
function paozao(){
console.log(arguments);
}
paozao(...F4)//相当于paozao('刘能','赵四','小沈阳','宋小宝')
扩展运算符的应用
1.数组的合并
const hello = ['h','e','l','l','o'];
const word = ['w','o','r','d'];
const helloword = hello.concat(word);
console.log(helloword)
- 数组的克隆
const copy = ['c','o','p','y'];
const copy2 = [...copy]
console.log(copy2)
- 将伪数组转化为真正的数组
const divs = document.querySelectorAll('div');
console.log(divs);
const divAll = [...divs];
console.log(divAll);
十一、symbol基本用法
Symbol
是一种新的原始数据类型,表示独一无二的值,时javascript语言的第七种数据类型,是一种类似于字符串的数据类型。
1. Symbol的值是唯一的,用来解决命名冲突的问题
2. Symbol值不能与其他的数据进行运算
3.Symbol定义的对象属性不能使用 for...in
遍历循环,但是可以使用 Reflect.ownKeys
来获取对象的所有键名。
|----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | let
s1 = Symbol();
console.log(s1,``typeof
s1);
let
l1 = ``'hello'``;
let
l2 = ``'hello'``;
console.log(l1 === l2);``//true
let
s2 = Symbol(``'hello'``);
let
s3 = Symbol(``'hello'``);
console.log(s2 === s3);``//false
Symbol.``for``创建
let
s4 = Symbol.``for``(``'nihao'``);
let
s5 = Symbol.``for``(``'nihao'``);
console.log(s4,``typeof
s4);
|
不能与其他数据进行运算
let result = s1 + 100;//Cannot convert a Symbol value to a number
let result = s1 > 100;//Cannot convert a Symbol value to a number
let result = s1 + '123';//Cannot convert a Symbol value to a string
let result = s1 + s1;//Cannot convert a Symbol value to a number
js常见数据类型总结:USONB: you are so niubility
- U:undefined
- S:string
- O:object
- B:boolean
声明对象
let methods = {
up:Symbol(),
down: Symbol()
};
game[methods.up] = function(){
console.log('我可以上升')
}
game[methods.down] = function(){
console.log('我可以下降')
}
console.log(game)
let lol = {
name:"英雄联盟",
[Symbol('yasuo')]:function(){
console.log("快乐风男");
},
[Symbol('jiansheng')]:function(){
console.log("无极剑圣")
}
}
console.log(lol)
Symbol内置属性,提供了11种内置属性
十二、迭代器
是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口就可以完成遍历操作
-
ES6提供了一种新的遍历命令
for...of
循环,iterator接口主要为for...of
服务 -
原生具备 Iterator接口的数据(可用 for of遍历)
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
3.工作原理
a.创建一个指针对象,指向当前数据结构的起始位置
b.第一次调用对象的next方法,指针自动指向数据结构的第一个成员
c.接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
d.每调用next方法返回一个包含 value和done属性的对象
注:需要自定义遍历数据的时候,要想到迭代器。
const person = ['张三','李四','王五'];
for(let v of person){
console.log(v);//'张三','李四','王五'
}
for(let v in person){
console.log(v);//0,1,2
}
for...of保存的键值,for...in保存的键名
let iterator = person[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
迭代器自定义遍历对象
const banji = {
name:"终极一班",
stus:[
'xiaoming',
'xiaohong',
'xiaotian',
'xioahu'
],
[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...of遍历,且返回的为对象中数组的成员
for(let v of banji){
console.log(v)
}
十三、生成器
生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同实际上就是一种特殊的函数,进行异步编程
声明方式,在function后面加 *
,调用时调用next()方法执行
生成器实现了iterator属性带有 next()
方法
yield语句函数代码的分隔符
function * gen(){
console.log("hello generator")
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一直没有尾巴';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
// console.log(iterator)
iterator.next();
iterator.next();
iterator.next();
iterator.next();
//遍历
for(let v of gen()){
console.log(v);
}
//生成器函数参数
function * gen(args){
console.log(args)
let one = yield 111;
console.log(one);
yield 222;
yield 333;
}
let iterator = gen('AAA');
console.log(iterator.next());
//next()方法可以传入实参,参数作为上一个yield语句返回结果
console.log(iterator.next('BBB'));
console.log(iterator.next());
console.log(iterator.next());
异步编程(js是单线程执行的,操作需要异步执行) 文件读取 网络操作(ajax
,request
) 数据库操作
生成器函数示例-1
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()
},1000)
}
function three (){
setTimeout(() =>{
console.log(333);
iterator.next()
},1000)
}
function * gen (){
yield one();
yield two();
yield three();
}
let iterator = gen();
iterator.next();
生成器函数示例-2
模拟获取(依次获取) 用户数据 订单数据 商品数据
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( executor){}
-
Promise.prototype.then
方法 -
Promise.prototype.catch
方法
使用方法
//实例化对象
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封装读取文件
const fs = require('fs');
const p = new Promise(function(resovle,reject){
fs.readFile("./resources/test.txt",(err,data)=>{
// 判断失败
if (err) reject(err);
// 成功
resovle(data);
});
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.error('操作失败');
})
- Promise发送ajax请求
const p = new Promise((resolve,reject) => {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open("GET","https://api.apiopen.top");
// 3.发送
xhr.send();
// 4.绑定事件,处理响应结果
xhr.onreadystatechange = function (){
// 处理逻辑
if(xhr.status >= 200 && xhr.status < 300){
// 响应成功
resolve(xhr.response);
}else{
// 响应失败
reject(xhr.status);
}
}
})
// 指定回调函数
p.then(function(value){
console.log(value)
},function(reason){
console.log(reason)
})
- Promise的then()方法
|-----------|-----------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 | const p = ``new
Promise((resolve,reject) =>{
``setTimeout(() =>{
``resolve(``'用户数据'``);
``},1000);
});
|
then指定回调函数,then方法的返回结果是 Promise对象,对象状态由回调函数的执行结果决定
如果回调函数中返回的结果是非 promise类型的属性,状态为成功,返回值为对象的成功的值
const result = p.then(value =>{
console.log(value);
1.非Promise类型的属性
return "good";
2.Promise类型的属性
return new Promise((resolve,reject) =>{
resolve('ok');
// reject('error');
});
3.抛出异常
throw new Error('出错了!');
},reason =>{
console.warn(reason);
});
console.log(result);
then()方法支持链式调用,链式调用可以解决回调地狱的问题
p.then(value=>{},reason=>{}).then(value={},reason=>{})
- Promise-读取多个文件
const fs = require('fs');
使用回调地狱的方式实现
fs.readFile('./resources/test.txt', (err, data1) => {
fs.readFile('./resources/test1.txt', (err, data2) => {
fs.readFile('./resources/test3.txt', (err, data3) => {
let result = data1 + '\r\n' + data2 + '\r\n' + data3;
console.log(result);
});
});
});
// 采用Promise对象的方式实现多文件读取,采用链式调用的方式进行拼接操作
const p = new Promise((reslove,reject)=>{
fs.readFile('./resources/test.txt',(err,data)=>{
reslove(data);
});
});
p.then(value=>{
return new Promise((reslove,reject)=>{
fs.readFile('./resources/test1.txt',(err,data)=>{
reslove([value,data]);
});
});
}).then(value=>{
return new Promise((reslove,reject)=>{
fs.readFile('./resources/test3.txt',(err,data)=>{
value.push(data);
reslove(value);
});
});
}).then(value=>{
console.log(value.join('\r\n'));
})
Promise的 catch()
方法,用于指定Promise对象失败时的回调是语法糖,相当于没有指定value参数的 then()
方法
const p = new Promise((reslove,reject)=>{
setTimeout(() => {
reject('出错啦!');
}, 1000);
});
// 通过then()方法的reason指定失败时的操作
p.then(value=>{},reason=>{
console.error(reason);
});
//通过catch()方法获取Promise对象的异常
p.catch(reason=>{
console.warn(reason);
})
十五、集合与相关的API
ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 Iterator接口,所以可以使用扩展运算符...
和 for...of...
进行遍历,
集合的属性和方法:
-
size 返回集合的元素个数
-
add 增加一个新元素,返回当前集合
-
delete 删除元素,返回 boolean值
-
has 检测集合中是否包含某个元素,返回 boolean值
//声明一个set
let s = new Set();
let s2 = new Set([12,13,14,15,21,12]);
// console.log(s ,typeof s);
console.log(s2);
// 1) size 返回集合的元素个数
console.log(s2.size);
// 2) add 增加一个新元素,返回当前集合
s2.add(100);
console.log(s2);
// 3) delete 删除元素,返回 boolean值
s2.delete(15);
console.log(s2);
// 4) has 检测集合中是否包含某个元素,返回 boolean值
console.log(s2.has(100));
// 5) clear 清空集合
s2.clear();
console.log(s2);
// 6)for..of..遍历
for(v of s2){
console.log(v);
}
//set集合的使用
let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let arr2 = [4,5,6,5,6];
//1.数组去重
let result = [...new Set(arr)];
console.log(result);
//2.交集
let result = [...new Set(arr)].filter(item =>{
let s2 = new Set(arr2);
if(s2.has(item)){
return true;
}else{
return false;
}
});
console.log(result);
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
console.log(result);
//3.并集
let union = [...new Set([...arr,...arr2])];
console.log(union);
//4.差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
十七、Class类
ES6提供了更接近传统语言的写法,引入了class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,
新的 class写法只是让对象原型的写l法更加清晰、更像面向对象编程的语法而己。
知识点:
-
class 声明类
-
constructor 定义构造函数初始化
-
extends 继承父类
-
super 调用父级构造方法
-
static 定义静态方法和属性
6.父类方法可以重写
//使用class()声明类
class Computer {
// 构造方法,名字不可修改,会在实例化对象的时候自动调用,可以没有
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
// 定义方法,不能使用ES5的方式声明
start() {
console.log('欢迎使用')
}
}
// 实例化对象
let lenovo = new Computer('lenovo', 5499);
console.log(lenovo)
lenovo.start();
class中的静态成员,属于类而不属于实例化对象
class Phone {
// 静态属性
static name = '手机'
// 静态方法
static call() {
console.log('我能打电话');
}
}
let huawei = new Phone;
console.log(huawei.name);//undifined
console.log(Phone.name);//手机
Phone.call();//我能打电话
huawei.call();//huawei.call is not a function
使用构造函数实现继承
//父类对象
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('拍照');
}
playGame() {
console.log('玩游戏');
}
// 子类重写父类的方法
call() {
console.log('视频通话');
}
}
const xiaomi = new SmartPhone('小米6', 1999, '白色', '5.15inch');
console.log(xiaomi);
// 子类不能调用父类的同名方法
xiaomi.call();
xiaomi.photo();
xiaomi.playGame();
class中get和set方法
class Phone{
// get对动态属性进行封装
get price (){
console.log('get方法被执行');
return 'get get get'
}
// set属性可以进行属性的判断和封装,需要设置形参
set price (newVal){
console.log('set方法执行');
console.log('新的价格为' + newVal);
}
}
let p = new Phone();
console.log(p.price);
p.price = 100;
十八、数值扩展
Number. EPSILON
是 JavaScript表示的最小精度EPSILON属性的值接近于2.2264466492503136884726361816E-16
多用于浮点数运算,用于解决浮点数计算误差问题
function equals(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(0.1 + 0.2 === 0.3);
console.log(equals(0.1 + 0.2, 0.3));
- 二进制和八进制
let b = 0b1010;//二进制
let o = 0177;//八进制
let d = 0x123;//16进制
console.log(b);
console.log(o);
console.log(d);
Number.isFinite
检测一个数值是否为有限数
console.log(Number.isFinite(100));//true
console.log(Number.isFinite(100/0));//false
Number.isNaN
检测一个数值是否为NaN
console.log(Number.isNaN(2));//false
console.log(Number.isNaN(NaN));//true
Number.parseInt
Number.parserFloat
字符串转整数
onsole.log(Number.parseInt('1323.1dcsdcd'));//1323
console.log(Number.parseFloat('13231.12dcsdcd'));//13231.12
Number.isInteger
判断一个数是否为整数
console.log(Number.isInteger(213.3));//false
console.log(Number.isInteger(213));//true
7.Math.trunc
将数字的小数部分抹掉
console.log(Math.trunc(12.3));
Math.sign
判断一个数到底为正数 负数 还是零
|-------|-----------------------------------------------------------------------------------------------------------|
| 1 2 3 | console.log(Math.sign(10));``//1
console.log(Math.sign(0));``//0
console.log(Math.sign(-10));``//-1
|
十九、对象方法扩展
Object.is
判断两个值是否完全相等,类似于===
但是可以判断NaN
是否相等
console.log(Object.is(110,110));//true
console.log(Object.is(110,10));//false
console.log(Object.is(NaN,NaN));//true
console.log(NaN === NaN);//false
Object.assign
对象的合并
const config1 = {
host: '127.0.0.1',
port:'3306',
user: 'user',
password: '123456',
test: 'test'
}
const config2 = {
host: '49.123.124.5',
port:'3306',
user: 'root',
password: 'root',
enviroment: 'dev'
}
console.log(Object.assign(config1,config2));
3.Object.setPrototypeof
Object.getPrototypeof
const school = {
name: 'SDUT'
}
const city = {
student: ['山东', '河北', '内蒙', '贵州', '杭州']
}
Object.setPrototypeOf(school, city);
console.log(Object.getPrototypeOf(school));
console.log(school);
二十、ES6的模块化
模块化:将大的程序文件,拆分成很多小的文件(模块),然后将小的文件组合起来
好处:防止命名冲突 代码复用 便于维护.
ES6模块化语法:
模块功能主要由两个命令构成: export
和 import
export
命令用于规定模块的对外接口
Import
命令用于输入其他模块提供的功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES6模块化测试</title>
</head>
<body>
<!-- 标签引入m1.js模块 -->
<script type="module">
//1.通用导入方式
// 引入m1.js模块
import * as m1 from "./js/m1.js";
console.log(m1);
console.log(m1.learn());
// 引入m2.js模块
import * as m2 from "./js/m2.js";
console.log(m2);
console.log(m2.study());
// 引入m3.js模块
import * as m3 from "./js/m3.js";
console.log(m3);
m3.default.change();
//2.解构赋值
import {name,learn} from './js/m1.js';
console.log(name);
console.log(learn);
// as使用别名的方式应用
import{name as lisi,study} from './js/m2.js';
console.log(lisi);
console.log(study);
// 引入默认暴露
import {default as m3} from './js/m3.js';
console.log(m3);
//3.简便形式,只针对默认暴露
import m3 from './js/m3.js';
console.log(m3);
</script>
<!-- 外部引入模块 -->
<script src="./js/app.js" type="module"></script>
</body>
</html>