let关键字
let
- 作用:
与var类似, 用于声明一个变量 - 特点:
在块作用域内有效
不能重复声明
不会预处理, 不存在提升 - 应用:
循环遍历加监听
使用let取代var是趋势
//console.log(age);// age is not defined
let age = 12;
//let age = 13;不能重复声明
console.log(age);
let btns = document.getElementsByTagName('button');
for(let i = 0;i<btns.length;i++){
btns[i].onclick = function () {
alert(i);
}
}
const关键字
- 作用:
定义一个常量 - 特点:
不能修改
其它特点同let - 应用:
保存不用改变的数据
const sex = '男';
console.log(sex);
//sex = '女';//不能修改
console.log(sex);
变量的解构赋值
- 理解:
从对象或数组中提取数据, 并赋值给变量(多个) - 对象的解构赋值
let {n, a} = {n:‘tom’, a:12} - 数组的解构赋值
let [a,b] = [1, ‘atguigu’]; - 用途
给多个形参赋值
//不解构
let obj = {
name: "ss",
age: 11
}
function person() {
console.log(obj.name, obj.age);
};
person();
//解构
let { name, age } = obj
function person1() {
console.log({ name, age });
}
person1();
let arr=["ss",2,true];
let [a,b,c]=arr;
console.log(a,b,c);
//3. 数组的解构赋值 不经常用
// let arr = ['abc', 23, true,1];
// let [a, b, c, d] = arr;
// console.log(a, b, c, d);
模板字符串
- 模板字符串 : 简化字符串的拼接
模板字符串必须用 `` 包含
变化的部分使用${xxx}定义
let obj = {
name : 'anverson',
age : 41
};
console.log('我叫:' + obj.name + ', 我的年龄是:' + obj.age);
console.log(`我叫:${obj.name}, 我的年龄是:${obj.age}`);
简化的对象写法
简化的对象写法
省略同名的属性值
省略方法的function
let x = 3;
let y = 5;
//普通写法
// let obj = {
// x : x,
// y : y,
// getPoint : function () {
// return this.x + this.y
// }
// };
//简化的写法
let obj = {
x,
y,
getPoint(){
return this.x
}
};
console.log(obj, obj.getPoint());
箭头函数
作用: 定义匿名函数
基本语法:
没有参数: () => console.log(‘xxxx’)
一个参数: i => i+2
大于一个参数: (i,j) => i+j
函数体不用大括号: 默认返回结果
函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
使用场景: 多用来定义回调函数
箭头函数的特点:
1、简洁
2、箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this
3、扩展理解: 箭头函数的this看外层的是否有函数,
如果有,外层函数的this就是内部箭头函数的this,
如果没有,则this是window。
//没有形参,并且函数体只有一条语句
let s = () => console.log("10");
s();
//一个形参,并且函数体只有一条语句
let s1 = x => console.log("11");
s1();
//形参是一个以上,且函数体只有一条语句
let s2 = (x, y) => x + y;
console.log(s2(1, 2));
//函数体有多条语句
let s3 = (x, y) => {
x * y;
console.log(s2(x, y));
return x * y;
};
console.log(s3(2, 3));
…运算符(三点运算符)
用途
- rest(可变)参数
用来取代arguments 但比arguments灵活,只能是最后部分形参参数
function add(…values) {
let sum = 0;
for(value of values) {
sum += value;
}
return sum;
} - 扩展运算符
let arr1 = [1,3,5];
let arr2 = [2,…arr1,6];
arr2.push(…arr1);
function foo(...value) {
console.log(arguments);
//arguments.callee(); //指向函数本身
//arguments没有数组的方法,所以报错
console.log(value);
value.forEach(function (item, index) {
console.log(item, index);
})
}
foo(2, 65);
//扩展运算符
let arr = [1, 6];
let arr1 = [2, 3, 4, 5];
//将arr与arr1合并
let arr2 = [1, ...arr1, 6]
console.log(...arr2);
形参默认值
形参的默认值----当不传入参数的时候默认使用形参里的默认值
function point(x = 0, y = 0) {
//如果没有传参,则默认值为零,传参不影响,会输出传入值;如果不给默认值,则会是undefined
this.x = x;
this.y = y;
y;
}
let p = new point(10, 12);
console.log(p);
let p1 = new point();
console.log(p1);
Promise
- 理解:
Promise对象: 代表了未来某个将要发生的事件(通常是一个异步操作)
有了promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称’回调地狱’)
ES6的Promise是一个构造函数, 用来生成promise实例 - 使用promise基本步骤(2步):
创建promise对象
let promise = new Promise((resolve, reject) => {
//初始化promise状态为 pending
//执行异步操作
if(异步操作成功) {
resolve(value);//修改promise的状态为fullfilled
} else {
reject(errMsg);//修改promise的状态为rejected
}
})
调用promise的then()
promise.then(function(
result => console.log(result),
errorMsg => alert(errorMsg)
))
- promise对象的3个状态
pending: 初始化状态
fullfilled: 成功状态
rejected: 失败状态 - 应用:
-
使用promise实现超时处理
-
使用promise封装处理ajax请求
let request = new XMLHttpRequest();
request.onreadystatechange = function () {
}
request.responseType = 'json';
request.open("GET", url);
request.send();
//创建一个promise实例对象
let promise = new Promise((resolve, reject) => {
//初始化promise的状态为pending---->初始化状态
console.log("111");//同步执行
//启动异步任务
setTimeout(() => {
console.log("222");
//resolve("yes");/修改promise的状态pending---->fullfilled(成功状态)
reject('no');//修改promise的状态pending----->rejected(失败状态)
}, 3000);
});
console.log("333");
promise.then((data) => {
console.log(data, "成功了...");
}, (error) => {
console.log(error, "失败了...");
})
Symbol
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
Symbol:
概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
特点:
1、Symbol属性对应的值是唯一的,解决命名冲突问题
2、Symbol值不能与其他数据进行计算,包括同字符串拼串
3、for in, for of遍历时不会遍历symbol属性。
使用:
1、调用Symbol函数得到symbol值
let symbol = Symbol();
let obj = {};
obj[symbol] = 'hello';
2、传参标识
let symbol = Symbol('one');
let symbol2 = Symbol('two');
console.log(symbol);// Symbol('one')
console.log(symbol2);// Symbol('two')
3、内置Symbol值
除了定义自己使用的Symbol
值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- Symbol.iterator
对象的Symbol.iterator属性,指向该对象的默认遍历器方法
//创建Symbol
let symbol = Symbol();
console.log(symbol);
//创建对象
let obj = { 'name': 'ss', 'age': 11 };
//向obj中添加symbol属性
obj[symbol] = 'hello';
//输出obj
console.log(obj);
//验证Symbol属性对应的值唯一
obj[symbol] = 'word';
console.log(obj);
//创建Symbol,并添加传参标识
let symbol1 = Symbol('a');
let symbol2 = Symbol('b');
//比较是否相等
console.log(symbol1 == symbol2);
// 验证for in无法遍历出Symbol属性
for (let i in obj) {
console.log(i);
}
iterator遍历器
概念: iterator是一种接口机制,为各种不同的数据结构提供统一的访问机制
作用:
1、为各种数据结构,提供一个统一的、简便的访问接口;
2、使得数据结构的成员能够按某种次序排列
3、ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费。
工作原理:
- 创建一个指针对象,指向数据结构的起始位置。
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
当遍历结束的时候返回的value值是undefined,done值为false
原生具备iterator接口的数据(可用for of遍历)
1、Array
2、arguments
3、set容器
4、map容器
5、String
。。。
window.onload = function () {
// 自定义iterator生成指针对象
function mockIterator(arr) {
let nextIndex = 0;
return {
next: function () {
return nextIndex < arr.length ? { value: arr[nextIndex++], done: false } : { value: undefined, done: true }
}
}
}
let arr = [1, 2, 3, 4, 5];
let iteratorObj = mockIterator(arr);
console.log(iteratorObj.next());
console.log(iteratorObj.next());
console.log(iteratorObj.next());
// 使用解构赋值以及...三点运算符时会调用iterator接口
let arr1 = [1, 2, 3, 4, 5];
let [value1, ...arr2] = arr1;
// yield*语句
function* generatorObj() {
yield '1'; // 可遍历数据,会自动调用iterator函数
yield '3';
}
let Go = generatorObj();
console.log(Go.next());
console.log(Go.next());
console.log(Go.next());
// 原生测试 数组
let arr3 = [1, 2, 'kobe', true];
for (let i of arr3) {
console.log(i);
}
// 字符串 string
let str = 'abcdefg';
for (let item of str) {
console.log(item);
}
}
Generator函数
Generator函数
概念:
1、ES6提供的解决异步编程的方案之一
2、Generator函数是一个状态机,内部封装了不同状态的数据,
3、用来生成遍历器对象
4、可暂停函数(惰性求值), yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
特点:
1、function 与函数名之间有一个星号
2、内部用yield表达式来定义不同的状态
例如:
function* generatorExample(){
let result = yield ‘hello’; // 状态值为hello
yield ‘generator’; // 状态值为generator
}
3、generator函数返回的是指针对象(接11章节里iterator),而不会执行函数内部逻辑
4、调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true}
5、再次调用next方法会从上一次停止时的yield处开始,直到最后
6、yield语句返回结果通常为undefined, 当调用next方法时传参内容会作为启动时yield语句的返回值。
function* generatorTest() {
console.log('函数开始执行');
yield 'hello';
console.log('函数暂停后再次启动');
yield 'generator';
}
// 生成遍历器对象
let Gt = generatorTest();
// 执行函数,遇到yield后即暂停
console.log(Gt); // 遍历器对象
let result = Gt.next(); // 函数执行,遇到yield暂停
console.log(result); // {value: "hello", done: false}
result = Gt.next(); // 函数再次启动
console.log(result); // {value: 'generator', done: false}
result = Gt.next();
console.log(result); // {value: undefined, done: true}表示函数内部状态已经遍历完毕
// 对象的Symbol.iterator属性;
let myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 4;
};
for (let i of myIterable) {
console.log(i);
}
let obj = [...myIterable];
console.log(obj);
async函数
async函数(ES7)
概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
本质: Generator的语法糖
语法:
async function foo(){
await 异步操作;
await 异步操作;
}
特点:
1、不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
2、返回的总是Promise对象,可以用then方法进行下一步操作
3、async取代Generator函数的星号*,await取代Generator的yield
4、语意上更为明确,使用简单
async function timeout(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
})
}
async function asyncPrint(value, ms) {
console.log('函数执行', new Date().toTimeString());
await timeout(ms);
console.log('延时时间', new Date().toTimeString());
console.log(value);
}
console.log(asyncPrint('hello async', 2000));
// await
async function awaitTest() {
let result = await Promise.resolve('执行成功');
console.log(result);
// let result2 = await Promise.reject('执行失败');
// console.log(result2);
let result3 = await Promise.resolve('还想执行一次');// 执行不了
console.log(result3);
}
awaitTest();
class
1. 通过class定义类/实现类的继承
2. 在类中通过constructor定义构造方法
3. 通过new来创建类的实例
4. 通过extends来实现类的继承
5. 通过super调用父类的构造方法
6. 重写从父类中继承的一般方法
class Person {
//调用类的构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
//定义一般的方法
showName() {
console.log(this.name, this.age);
}
}
let person = new Person('kobe', 39);
console.log(person, person.showName());
//定义一个子类
class StrPerson extends Person {
constructor(name, age, salary) {
super(name, age);//调用父类的构造方法
this.salary = salary;
}
showName() {//在子类自身定义方法
console.log(this.name, this.age, this.salary);
}
}
let str = new StrPerson('weide', 38, 1000000000);
console.log(str);
str.showName();
字符串扩展
- includes(str) : 判断是否包含指定的字符串
- startsWith(str) : 判断是否以指定字符串开头
- endsWith(str) : 判断是否以指定字符串结尾
- repeat(count) : 重复指定次数
let str = 'abcdefg';
console.log(str.includes('a'));//true
console.log(str.includes('h'));//false
//startsWith(str) : 判断是否以指定字符串开头
console.log(str.startsWith('a'));//true
console.log(str.startsWith('d'));//false
//endsWith(str) : 判断是否以指定字符串结尾
console.log(str.endsWith('g'));//true
console.log(str.endsWith('d'));//false
//repeat(count) : 重复指定次数a
console.log(str.repeat(5));
数值扩展
- 二进制与八进制数值表示法: 二进制用0b, 八进制用0o
- Number.isFinite(i) : 判断是否是有限大的数
- Number.isNaN(i) : 判断是否是NaN
- Number.isInteger(i) : 判断是否是整数
- Number.parseInt(str) : 将字符串转换为对应的数值
- Math.trunc(i) : 直接去除小数部分
console.log(0b1010);//10
console.log(0o56);//46
//Number.isFinite(i) : 判断是否是有限大的数
console.log(Number.isFinite(NaN));//false
console.log(Number.isFinite(5));//true
//Number.isNaN(i) : 判断是否是NaN
console.log(Number.isNaN(NaN));//true
console.log(Number.isNaN(5));//falsse
//Number.isInteger(i) : 判断是否是整数
console.log(Number.isInteger(5.23));//false
console.log(Number.isInteger(5.0));//true
console.log(Number.isInteger(5));//true
//Number.parseInt(str) : 将字符串转换为对应的数值
console.log(Number.parseInt('123abc'));//123
console.log(Number.parseInt('a123abc'));//NaN
// Math.trunc(i) : 直接去除小数部分
console.log(Math.trunc(13.123));//13
数组扩展
- Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
- Array.of(v1, v2, v3) : 将一系列值转换成数组
- find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
- findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
//Array.from(v) : 将伪数组对象或可遍历对象转换为真数组
let btns = document.getElementsByTagName('button');
console.log(btns.length);//3
Array.from(btns).forEach(function (item, index) {
console.log(item, index);
});
//Array.of(v1, v2, v3) : 将一系列值转换成数组
let arr = Array.of(1, 'abc', true);
console.log(arr);
//find(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素
let arr1 = [1,3,5,2,6,7,3];
let result = arr1.find(function (item, index) {
return item >3
});
console.log(result);//5
//findIndex(function(value, index, arr){return true}) : 找出第一个满足条件返回true的元素下标
let result1 = arr1.findIndex(function (item, index) {
return item >3
});
console.log(result1);//2
对象扩展
- Object.is(v1, v2)
判断2个数据是否完全相等 - Object.assign(target, source1, source2…)
将源对象的属性复制到目标对象上 - 直接操作 proto 属性
let obj2 = {};
obj2.proto = obj1;
console.log(Object.is('abc', 'abc'));//true
console.log(NaN == NaN);//false
console.log(Object.is(NaN, NaN));//true
console.log(0 == -0);//true
console.log(Object.is(0, -0));//false
//Object.assign(target, source1, source2..)
let obj = { name: 'kobe', age: 39, c: { d: 2 } };
let obj1 = {};
Object.assign(obj1, obj);
console.log(obj1, obj1.name);
//直接操作 __proto__ 属性
let obj3 = { name: 'anverson', age: 41 };
let obj4 = {};
obj4.__proto__ = obj3;
console.log(obj4, obj4.name, obj4.age);
对象的深度克隆
1、数据类型:
* 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
- 基本数据类型:
特点: 存储的是该对象的实际数据
- 对象数据类型:
特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
2、复制数据
- 基本数据类型存放的就是实际的数据,可直接复制
let number2 = 2;
let number1 = number2;
- 克隆数据:对象/数组
1、区别: 浅拷贝/深度拷贝
判断: 拷贝是否产生了新的数据还是拷贝的是数据的引用
知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
let obj = {username: ‘kobe’}
let obj1 = obj; // obj1 复制了obj在栈内存的引用
2、常用的拷贝技术
1). arr.concat(): 数组浅拷贝
2). arr.slice(): 数组浅拷贝
3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
4). 浅拷贝包含函数数据的对象/数组
5). 深拷贝包含函数数据的对象/数组
// 复制的对象的方式
// 浅度复制
let obj = {username: 'kobe', age: 39, sex: {option1: '男', option2: '女'}};
let obj1 = obj;
console.log(obj1);
obj1.sex.option1 = '不男不女'; // 修改复制的对象会影响原对象
console.log(obj1, obj);
console.log('-----------');
// Object.assign(); 浅复制
let obj2 = {};
Object.assign(obj2, obj);
console.log(obj2);
obj2.sex.option1 = '男'; // 修改复制的对象会影响原对象
console.log(obj2, obj);
// 深度克隆(复制)
function getObjClass(obj) {
let result = Object.prototype.toString.call(obj).slice(8, -1);
if(result === 'Null'){
return 'Null';
}else if(result === 'Undefined'){
return 'Undefined';
}else {
return result;
}
}
// for in 遍历数组的时候遍历的是下标
let testArr = [1,2,3,4];
for(let i in testArr){
console.log(i); // 对应的下标索引
}
// 深度克隆
function deepClone(obj) {
let result, objClass = getObjClass(obj);
if(objClass === 'Object'){
result = {};
}else if(objClass === 'Array'){
result = [];
}else {
return obj; // 如果是其他数据类型不复制,直接将数据返回
}
// 遍历目标对象
for(let key in obj){
let value = obj[key];
if(getObjClass(value) === "Object" || 'Array'){
result[key] = deepClone(value);
}else {
result[key] = obj[key];
}
}
return result;
}
let obj3 = {username: 'kobe',age: 39, sex: {option1: '男', option2: '女'}};
let obj4 = deepClone(obj3);
console.log(obj4);
obj4.sex.option1 = '不男不女'; // 修改复制后的对象不会影响原对象
console.log(obj4, obj3);
Set和Map数据结构
- Set容器 : 无序不可重复的多个value的集合体
- Set()
- Set(array)
- add(value)
- delete(value)
- has(value)
- clear()
- size
- Map容器 : 无序的 key不重复的多个key-value的集合体
- Map()
- Map(array)
- set(key, value)//添加
- get(key)
- delete(key)
- has(key)
- clear()
- size
let set = new Set([1,2,3,4,3,2,1,6]);
console.log(set);
set.add('abc');
console.log(set, set.size);
//delete(value)
set.delete(2);
console.log(set);
//has(value)
console.log(set.has(2));//false
console.log(set.has(1));//true
//clear()
set.clear();
console.log(set);
let map = new Map([['abc', 12],[25, 'age']]);
console.log(map);
map.set('男', '性别');
console.log(map);
console.log(map.get(25));//age
//delete(key)
map.delete('男');
console.log(map);
console.log(map.has('男'));//false
console.log(map.has('abc'));//true
map.clear();
console.log(map);
for_of循环
for(let value of target){}循环遍历
- 遍历数组
- 遍历Set
- 遍历Map
- 遍历字符串
- 遍历伪数组
<script type="text/javascript">
window.onload = function () {
//遍历数组
let arr = [1, 2, 3, 4, 5];
for (let num of arr) {
console.log(num);
}
//遍历Set
let set = new Set([1, 2, 3, 4, 5]);
for (let num of set) {
console.log(num);
}
//遍历Map
let map = new Map([[1,'a'],[2,'b']]);
for (let num of map) {
console.log(num);
}
//遍历字符串
let str = 'abcdefg';
for (let num of str) {
console.log(num);
}
//遍历伪数组
let btns = document.getElementsByTagName('button');
for (let btn of btns) {
console.log(btn.innerHTML);
}
}
</script>
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
</body>
ES7的一个补充
- 指数运算符(幂): **
- Array.prototype.includes(value) : 判断数组中是否包含指定value
console.log(3 ** 3);//27
let arr = [1, 2, 3, 4, 'abc'];
console.log(arr.includes(2));//true
console.log(arr.includes(5));//false
console.log(arr.includes(4));//true