一、
let命令:用来声明一个变量,和var非常类似
const命令:用来声明一个常量,常量就是不可变的量
用let声明变量注意事项:
1.使用let声明的变量,所声明的变量只在命令所在的代码块内有效
<script type="text/javascript">
{
let a = 10;
//alert(a)
var b = 10;
}
//alert(a)报错
alert(b)//10
</script>
2.使用let命令声明的变量在域解析的时候不会被提升
console.log(a)//undefined
var a = 10;
console.log(b)//报错
let b = 10;
3.let不允许在同一个作用域下生明已经存在的变量
//var a = 10;
//var a;//不报错
let a = 10;
let a;//报错
4.let在for循环中的运用
var btn = document.querySelectorAll('input');
for(var i = 0; i < btn.length; i++) {
btn[i].onclick = function() {
console.log(i)//5
this.style.background = 'red';
}
}
/*for(var i = 0; i < btn.length; i++) {
btn[i].index = i;
btn[i].onclick = function() {
console.log(this.index)//0123
btn[this.index].style.background = 'red';
}
}*/
/*for(let i = 0; i < btn.length; i++) {
btn[i].onclick = function() {
console.log(i)//012345
this.style.background = 'red';
}
}*/
在循环语句中是一个父作用域,在循环体之中是一个子作用域
for(let i=0;i<3;i++){
let i = 10;
console.log(i)//10 父作用域与子作用域是分离的
}
console.log(i)//报错 let出来的变量只在循环语句中有用,在之外就未定义报错了
const命令同样有let的123条特点,第一所声明的常量只在其所在的代码块内有效,第二声明的常量不会被提升,第三 不能声明已经被声明过的变量或者常量。还有两点:
1.声明的时候必须赋值
var a;//正常
let b;//正常
const c;//报错
2.声明的常量储存简单的数据类型时候不可改变其值,如果储存的是对象,那么引用不可以被改变,至于对象里面的数据如何变化,是没有关系的。
/*const a = 10;
const a = 52;*/
const obj = {a : 10}
obj.a = 20;
二、
变量的结构赋值:本质上就是一种匹配模式,只要等号两边的模式相同,那么左边的变量就可以被赋予对应的值;
结构赋值主要分为:
1.数组的结构赋值
/*let [a,[[b],c]] = [1,[[2],3]]
console.log(a,b,c) //1,2,3*/
/*let [,,a] = [1,2,3]
console.log(a)//3*/
let [y = 1] = [];
console.log(y)//1
2.对象的结构赋值
//let {a,b} = {b : 'bbb',a: 'aaa'}
//console.log(a,b) //aaa bbb
let {a : b} = {a : 1}
console.log(a)//报错
//console.log(b)//1
3.基本类型的结构赋值
//let [a,b,c,d] = '1234';
//console.log(a,b,c,d)//1,2,3,4
//let {length:len} = 'tangxiaoqiang';
//console.log(len)//13
//let {toString:ts} = 1;
//let {toString:bs} = true;
//console.log(ts === Number.prototype.toString)//true
//console.log(bs === Boolean.prototype.toString)//true
//null和undefined 不能进行结构赋值
let {a} = null;//报错
三、
数据结构Set
集合的基本概念:
集合是由一组无序且唯一(即不重复)的项组成的。这个数据结构使用了与有限集合相同的数学概念,应用在计算机的数据结构中。
特点:key 和 vaule 相同,没有重复的value.
ES6提供了数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
1.如何创建一个Set
//const a = new Set([1,2,3])
//console.log(a)//Set(3) {1, 2, 3}
2.Set类的属性
const a = new Set([1,2,3])
console.log(a.size)//3 size类似与length
3.Set类的方法
const a = new Set([1,2,3])
//1.set.add(value) 添加一个数据,返回Set结构本身
//a.add('a').add('b').add('c')
//console.log(a)//{1, 2, 3, "a", "b","c"}
//2.set.delete(value) 删除指定数据,返回一个布尔值,表示删除是否成功
//console.log(a.delete(1));//true
//console.log(a)//2,3
///console.log(a.delete(1));//false
//3.set.has(value) 判断该值是否为Set的成员,返回一个布尔值
//console.log(a.has(1))//false
//console.log(a.has(2))//true
//4.set.clear()清除所有的数据,没有返回值
//a.clear()
//console.log(a)
//5.keys() 返回键值的遍历器
//console.log(a.keys())
//6.values() 返回键值的遍历器
//console.log(a.values())
//7.entries()返回键值对的遍历器
//console.log(a.entries())
//8.forEach() 使用回调函数遍历每个成员
/*a.forEach(function(value,key,set){
console.log(value + 'tjx')
})
console.log(a)*/
//Set不允许有重复的数据的
a.add(1);
console.log(a)//1,2,3
四、
数据结构Map
字典:是用来存储不重复key的Hash结构。不同于集合(Set)的是,字典使用的是[键,值]的形式来存储数据的。
javascript的对象(Object:{})只能用字符串当作键。这给它的使用带来了很大的限制。
为了解决这个问题,ES6提供了Map数据结构。它类似与对象,也是键值对的集合,但是‘键’的范围不限制于字符串,各类数据的值(包括对象)都可以当作键,也就是说,Object结构提供了“字符串-值”的对应,Map结构提供了“值-值”的对应,是一种更加完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object跟合适。
1.如何创建Map
const map = new Map([
['a',1],
['b',2]
])
//console.log(map)//{"a" => 1, "b" => 2}*/
2.Map类的属性
const map = new Map([
['a',1],
['b',2]
])
console.log(map.size)//2
3.Map类的方法
1.set(key,value)设置键名key对应的键值为value,然后返回整个Map结构。如果已有值,则键值会被更新,否则就新生成该键。
2.get(key)get方法读取key对应的键值,如果找不到key,返回undefined.
3.delete(key)删除某个键,返回true,如果删除失败返回false.
4.has(key)方法返回一个布尔值,表示某个键是否在当前Map对象之中。
5.clear()清除数据,没有返回值。
6.keys()返回键名的遍历器
7.values()返回键值的遍历器
8.entries()返回键值对的遍历器
9.forEach()使用回调函数遍历每个成员
//1.set(key,value)设置键名key对应的键值为value,然后返回整个Map结构。如果已有值,则键值会被更新,否则就新生成该键。
const map = new Map([
['a', 1],
['b', 2]
])
map.set('miaov', 'ketang').set('new', 'www').set('miaov', 'body');
console.log(map) //重复写对个相同key会被后面的值覆盖
//2.get(key)get方法读取key对应的键值,如果找不到key,返回undefined.
console.log(map.get('new'))
console.log(map.get('aa'))
//3.delete(key)删除某个键,返回true,如果删除失败返回false.
console.log(map.delete('new')) //true
console.log(map)
console.log(map.delete('new')) //false
//4.has(key)方法返回一个布尔值,表示某个键是否在当前Map对象之中。
console.log(map.has('new')) //false
map.set('new', '添加了')
console.log(map.has('new')) //true
//5.clear()清除数据,没有返回值。
//map.clear()
//console.log(map) //{}
//6.keys()返回键名的遍历器
console.log(map.keys())
//7. values() 返回键值的遍历器
console.log(map.values())
//8.entries() 返回键值对的遍历器 !!!!
console.log(map.entries())
//9. forEach() 使用回调函数遍历每个成员
map.forEach(function(key,value,map){
console.log(key + ':' + value)
})
//Map在使用的一些注意事项:
//map.set(NaN,10).set(NaN,100)
//console.log(map)//NaN,100
map.set({},'a').set({},'b')
console.log(map) //Object {} => "a" Object {} => "b"
console.log({} === {})//false 比较的不是值而是内存地址所以不相等
//map里面key的排列顺序永远都是按照添加的顺序排列的
五、
Iterator:
基本概念:
在ES6中新增了Set和Map两种数据结构,在加上JS之前原有的数组和对象,这样就有了四种数据集合,平时还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象等,这样就需要一种统一的接口机制,来处理所有不同的数据结构。
Iterator就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作,而且这种遍历操作是***依次*处理该数据结构的所有成员。
Iterator遍历器的作用:
-为各种数据结构,提供一个统一的,简便的访问接口。
- 使得数据结构的成员都能够按照某种次序排列
- ES6新增了遍历命令for...of循环,Iterator接口主要提供for..of消费
Iterator的遍历过程:
-创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
-第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
-第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
- 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
第一次调用next方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属于是一个布尔值,表示遍历是否结束。
//1.手写Iterator接口
/*const arr = [1,2,3];
function iterator(arr){
let index = 0;
return {
next:function(){
return index < arr.length ?
{value : arr[index++],done:false}:
{value : undefined,done:true};
}
}
}
const it = iterator(arr);
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());*/
//2.凡是具有Symbol.iterator属性的数据结构都具有Iteratorjiek
const arr = [1,2,3];
const set = new Set(['a','b','c']);
const map = new Map([['a',1]]);
const itArr = arr[Symbol.iterator]();
const itSet = set[Symbol.iterator]();
const itMap = map[Symbol.iterator]();
console.log(itArr);
console.log(itSet);
console.log(itMap);
console.log(itSet.next());
console.log(itSet.next());
console.log(itSet.next());
console.log(itSet.next());
const obj = {};
console.log(obj[Symbol.iterator]);//undefined
/*3.具备iterator接口的数据结构都可以进行下操作:
-结构负值
-扩展运算符*/
//let [x,y] = set;
//console.log(x,y)//a b
//...
let str = 'miaov';
let arrStr = [...str];
//console.log(arrStr)//["m", "i", "a", "o", "v"]
//数组去重
const arr2 = [{},[],1,1,'a','a',1,2];
console.log([...new Set(arr2)])//数组 [Object, Array(0), 1, "a", 2]
console.log(new Set(arr2))//集合 {Object {}, [], 1, "a", 2}
//4.for..of循环
const ofArr = [1,2,3,4];
for(let i of ofArr){
console.log(i)
}
const m = new Map();
m.set('a',1).set('b',2).set('c',3);
for(let data of m){
console.log(data)
}
for(let [key,value] of m){
console.log(key,value)
}
六、
class:
js语言的传统方法是通过构造函数,定义并且生成新的对象,是一种基于原型的面相对象系统:这种写法跟传统的面向对象语言(比如c++和java)差异很大,很容易让新学习这门语言的人感到困惑,所以,在ES6中新增加了类的概念,可以使用class关键字声明一个类,之后这个类来实例化对象。
//ES5的构造函数
/*const Miaov = function(a,b){
this.a = a;
this.b = b;
return this;
};
Miaov.prototype = {
constructor : Miaov,
print:function(){
console.log(this.a+' '+this.b)
}
};
const miaov = new Miaov('hello','world').print()*/
//ES6的写法
class Miaov {
constructor(a,b){
this.a = a;
this.b = b;
return this;
}
print(){
console.log(this.a+' '+this.b)
}
};
const miaov = new Miaov('hello','world').print()
console.log(typeof Miaov)
//1.Miaov中的constructor方法是构造方法,this关键字则代表实例对象。也就是说es5的构造函数Miaov,对应ES的Miaov这个类的构造方法。
//2Miaov这个类除了构造方法,还定义了一个print方法,注意,定义‘类’的方法的时候,前面不需要加上function这个关键字,直接吧函数定义放进去就可以啦,另外方法之间不需要逗号分隔,加了会报错。
//3构造函数的prototype属性,在ES6的‘类’上面继续存在,而且类的所有方法都定义在类的prototype属性上面
console.log(Miaov.prototype)
//4定义在类的方法都是不可以枚举的
console.log(Object.keys(Miaov.prototype))
//5.constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显示定义,一个空的constructor方法会被默认添加
class P {};
const p = new P();
console.log(p);
//6.生成类的实例对象的写法,与ES5完全一样,也是使用new命令,如果忘记加上new,像函数那样调用class,将会报错
//p();
七、
Symbol:
什么是Symbol?
Symbol表示独一无二的值。他是JS中第七种数据类型。
基本的数据类型:Null Undefined Number Boolean String Symbol
引用数据类型;Object
let s1 = Symbol();
let s2 = Symbol();
console.log(typeof s1)//'symbol'
console.log(s1 === s2)//false
//Symbol函数前不能使用new否则会报错,原因在于Symbol是一种原始类型的值,不是对象。
//let s3 = new Symbol();
console.log(s1)
console.log(s2)
//Symbol函数接收一个字符串作为参数,表示对Symbol的描述,主要是为了在控制台显示,或者转为字符串的时候,比较容易区分
/*let s3 = Symbol('miaov');
let s4 = Symbol('leo');
console.log(s3,s4)//Symbol(miaov) Symbol(leo)、
console.log(Symbol('momo') === Symbol('momo'))*///false 参数仅仅只是一个描述
//2 Symbol数据类型的转换
console.log(String(Symbol('miaov')))//Symbol(miaov)
console.log(Symbol('leo').toString())//Symbol(leo)
console.log(!!Symbol())//true
//console.log(Number(Symbol()))//报错
//console.log(Symbol('ttt') + 'txj')//报错 和字符串不可以进行拼接
//console.log(Symbol('miaov')*100)//报错 不能做任何运算
//3.作为对象的属性名
/*let yyy = Symbol('yyy');
const obj = {};
obj[yyy] = 'hello';
console.log(obj)
console.log(obj[yyy])*/
/*let ss =Symbol('ss');
const data = {
[ss]:'miaov'
}
console.log(data)
console.log(data[ss])*/
const data = {
[Symbol()]:123,
a : 1,
b : 2
}
//console.log(data[Symbol()]);//获取不到
//Symbol不能被for...in循环遍历,虽然不能被遍历,但是也不是私有的属性,可以通过Object.getOwnPropertySymbols方法获得一个对象的所有的Symbol属性
for(let i in data ){
console.log(i)//a,b
}
console.log(Object.getOwnPropertySymbols(data))
console.log(data[Object.getOwnPropertySymbols(data)[0]])
八、
内置对象的扩展:
字符串扩展
//模版字符串 ``
let fa = true;
let html = `<ul>
<li>
<span>${'首页'}</span>
<span></span>
<span class="${fa ? 'show' : 'hide'}"></span>
<span></span>
<span></span>
</li>
</ul>`;
console.log(html)
/*1.repeat()返回值为布尔值
2.includes()查找字符串中是否包含字符串 返回值为布尔值
startsWidth()查找字符串开头是否包含字符串
endsWidth()查找字符串结尾是否包含字符串
*/
/*let str1 = 'a';
let str2 = str1.repeat(3) //传入参数为个数
console.log(str2)*/
let str = 'miaov';
console.log(str.includes('ao'))//true
console.log(str.includes('b'))//false
console.log(str.startsWith('m'))//true
console.log(str.startsWith('i'))//false
console.log(str.endsWith('aov'))//true
数组的扩展
//数组的扩展
//Array.from() 转换成数组
/*var lis = document.querySelectorAll('li');
console.log(Array.isArray(lis))//false
let lis2 = Array.from(lis)
console.log(lis2);
console.log(Array.isArray(lis2))//true
//Array.of()创建数组
const arr = Array.of(1);
console.log(arr)//true*/
//find()查找数组中符合要求的元素,并且返回数组中第一个符合要求的元素 都不符合返回undefined
//findIndex()查找数组中符合要求的元素,并且返回数组中第一个符合要求的元素的下标 都不符合返回-1;
/*const arr = [1,2,3,4]
let res = arr.find(function(a){
return a<0;
})
console.log(res)//1 元素*/
/*let res = arr.findIndex(function(a){
return a<2;
})
console.log(res)//0 下标*/
//fill()
/*const arr = [1,2,3,4];
arr.fill('aaa',1,3)
console.log(arr)//[1, "aaa", "aaa", 4]*/
对象的扩展
//对象的简洁表示法
let a = 1;
/*const obj = {
a : a
}
console.log(obj) //Object {a: 1}
const obj = {a}
console.log(obj)//Object {a: 1}*/
/*const obj = {
fn : function(){
console.log(1)
},
fn2(){
console.log(2)
}
}
obj.fn();//1
obj.fn2();//2
*/
//Object.is() 判断两个对象是否一样 就是样子一样
console.log(Object.is(NaN,NaN))//true
console.log(Object.is(+0,-0))//false
//Object.assign()
//用于对象的合并,将原对象所有可以枚举属性,复制到目标对象
let obj1 = {a:1};
let obj2 = {a:2,b:3};
let obj3 = {c : 'abc'};
//Object.assign(目标对象,源对象,源对象...)
Object.assign(obj1,obj2,obj3)
console.log(obj1) //{a: 2, b: 3, c: "abc"}
//目标元素相同属性名的会被源对象的相同的覆盖
九、
函数的扩展:
//函数的扩展
//1.为函数参数指定默认值
/*function fn(a,b){
a = a || 10;
b = b || 20;
console.log(a + b);
}
fn();//30
fn(0,10)//20*/
/*function fn(a = 10,b = 20){
console.log(a + b);
}
fn();//30
fn(0,10)//10*/
//2.函数的rest参数
//rest 参数形式为(“...变量名”),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
/*function sum(){
var args = arguments;
var res = 0;
for(var i = 0;i<args.length;i++){
res += args[i];
}
console.log(res)
}
sum(1,2)//3*/
/*function sum(a,...arr){//...arr后面在写参数就会报错
var res = a;
for(var i=0;i<arr.length;i++){
res += arr[i];
}
console.log(res)
}
sum(10,1,2,3)//16*/
//3.箭头函数
//使用‘箭头’(=>)定义函数
/*const fn = a => a;
const fn2 = function(a){
return a;
}
console.log(fn(1))//1
console.log(fn2(1))//1*/
//const fn = (a,b) => a + b;
//console.log(fn(1,2))//3
/*const fn = (a,b) => {
a = a * 2;
b = b * 2;
return a + b;
};
console.log(fn(1,2))//6*/
//const fn = (a,b) =>({a,b});
//console.log(fn(1,2))//Object {a: 1, b: 2}
//var arr = [1,2,4,3,7,0];
/*arr.sort(function(a,b){
return a - b;
})
console.log(arr)*///[0, 1, 2, 3, 4, 7]
//arr.sort((a,b) => a - b);
//console.log(arr)//[0, 1, 2, 3, 4, 7]
//1箭头函数体内没有自己的this对象,所以在使用的时候,其内部的this就是定义时所在的环境对象,而不是使用时所在环境对象
/*function fn(){
setTimeout(function(){
console.log(this);//Window
},1000)
setTimeout(() => {
console.log(this)//Object {a: 1}
},1000)
}
var obj = {a : 1};
fn.call(obj);*/
//不能给箭头函数使用 call applu bind 去改变其内部的this指向
//2箭头函数体内没有arguments对象,如果要用,可以用Rest参数代替
/*function fn(){
setTimeout(() => {
console.log(arguments)
},1000)
}
fn(1,2,3)*/
//const fn =(...arr) => arr;
//console.log(fn(1,2,3,4));//[1, 2, 3, 4]
//3不可以当作构造函数,不可以使用new命令,否则会抛出一个错误
// const fn = (a,b) => a + b;
//const f = new fn(1,2)//报错
//4 箭头函数不能用作Generator函数
十、
异步操作之Promise:
Promise:是ES6中新增的异步编程解决方案,体现在代码中他是一个对象,可以通过Promise构造函数来实例化。
new Promise(cb) === > 实例的基本使用 Pending Resolved Rejected
两个原型方法:
- Promise.prototype.then()
- Promise.prototype.catch()
两个常用的静态方法:
- Promise.all()
- Promise.resolve()
new Promise(cb)
pending(进行中) ===>Resolved(已完成)
Pending(进行中) ===>Rejected(已失败)
const imgs = [
'http://att.img.xiushuang.com/allimg/160712/16015312A-0.jpg',
'http://file20.mafengwo.net/M00/19/20/wKgB3FGj_XOARavMAADwfO6Uxgw93.jpeg',
'http://i2.hdslb.com/bfs/archive/795cbe9de1cc6c6b76ffb65ca3ec52bff3cf1af7.jpg',
'http://img.bimg.126.net/photo/O6mJjq5DOgYqQDpfuqx0WQ==/2319072333119924755.jpg'
];
/*const p = new Promise(function(resolve,reject){
const img = new Image();
img.src = '';
img.onload = function(){
resolve(this);
};
img.onerror = function(err){
reject(new Error('图片加载失败'))
};
});
console.log(123)
p.then(function (img){
console.log('完成')
document.body.appendChild(img)
}).catch(function(err){
console.log(err)
})
console.log(456)*/
function loadImg(url){
const p = new Promise(function(resolve,reject){
const img = new Image();
img.src = url;
img.onload = function(){
resolve(this);
};
img.onerror = function(err){
reject(new Error('图片加载失败'))
};
});
return p;
}
/*loadImg(imgs[2]).then(function(img){
document.body.appendChild(img)
})*/
/*Promise.all可以将多个Promise实例包装成一个新的Promise实例;
-当所有Promise实例的状态都变成resolved,Promise.all的状态才会变成resolved,此时返回值组成一个数组,传递给then中的resolve函数.
-只要其中有一个被rejected,Promise.all的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数.*/
/*const allDone = Promise.all([loadImg(imgs[0]),loadImg(imgs[1]),loadImg('')]);
allDone.then(function(datas){
datas.forEach(function(item,i){
document.body.appendChild(item)
});
}).catch(function(err){
console.log(err)
})*/
//参数是Promise实例,将不做任何修改,原封不动的返回这个实例
/*Promise.resolve(loadImg(imgs[0])).then(function(img){
document.body.appendChild(img)
})*/
/*Promise.resolve({
then(resolve,reject){
const img = new Image();
img.src = imgs[1];
img.onload = function(){
resolve(this);
}
}
}).then(function(img){
document.body.appendChild(img)
})*/
/*Promise.resolve('miaov').then(function(str){
console.log(str)
})*/
const p = Promise.resolve();
console.log(p)