let const 和 var
ES6开始用let代替var,新增const作为定义变量的关键字。
- var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
- let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
- const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
var
var定义的变量,在if和for没有块级作用域,在内部改变变量会影响到外部的变量。
var在全局定义的变量不仅在全局上定义了一个变量,还会给GO添加一个属性即在window上新增一个属性,两者形成映射机制。
let
let定义的变量,在if和for有了块级作用域,在内部改变变量不再影响到外部的变量。
let定义的仅仅是全局变量。
let定义的变量不再是window所有,ES6中多了一个script的作用域,let和const的变量都在里面。
const
被const定义的变量,是一个常量,定义以后不可以再赋值,他的内存地址不可修改。
解构赋值
解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
数组解构
let ary = [1,2,3];
let [a,b,c] = ary;
console.log(a,b,c);//1 2 3
使用...
let [n, ...m] = [11,22,33,44]
console.log(n)//11
console.log(m)//[22,33,44]
对象解构
let person = {
name:'zhangshan',
age:20
}
let {name, age} = person;//变量名与对象属性名一样
console.log(name,age);//zhangshan 20
/*-----------------------------------------------------------*/
let person = {
name:'zhangshan',
age:20
}
let {name : myname, age : myage} = person;//变量名与对象属性名不一样
console.log(myname,myage);//zhangshan 20
有默认值的解构
var a, b;
[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7
...
的使用
剩余运算符
剩余参数语法允许我们将一个不定量的参数表示为一个数组。
function sum(num, ...arg){
console.log(num);
console.log(arg);
}
sum(1,2,3,4,5)//1 , [2,3,4,5]
在箭头函数中没有arguments,我们可以使用...arg代替arguments
剩余参数+解构赋值
let arr = [1,2,3,4,5];
let [a,...b] = arr
console.log(a,b);//1 , [2,3,4,5]
展开运算符
将数组或对象转为用逗号分割的参数序列。
let arr = [1,2,3,4,5];
let obj = {
name:'qqq',
age:20
}
console.log(...arr);//1 2 3 4 5
拓展运算符
把伪数组转换为真正的数组
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</body>
<script>
var div = document.getElementsByTagName('div');
var arr = [...div];
console.log(arr);
</script>
Set和Map
Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数用来生成Set数据结构。
const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
参数
Set()
可接受一个数组或者其他可迭代的数据类型作为参数用来初始化。
const s = new Set([1,2,3,3,4]);
console.log(s);//{1,2,3,4...}
向 Set 加入值的时候,不会发生类型转换,所以5
和"5"
是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===
),主要的区别是向 Set 加入值时认为NaN
等于自身,而精确相等运算符认为NaN
不等于自身。
let set = new Set();
let a = NaN;
let b = NaN;
let c = 5;
let d = "5";
set.add(a).add(b).add(c).add(d);
console.log(set)// Set {NaN,5,"5"}
Set的实例属性和方法
属性
-
Set.prototype.constructor
:构造函数,默认就是Set
函数。 -
Set.prototype.size
:返回Set
实例的成员总数。
方法
操作方法
-
Set.prototype.add(value)
:添加某个值,返回 Set 结构本身。 -
Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。 -
Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员。 -
Set.prototype.clear()
:清除所有成员,没有返回值。
遍历方法
Set的键名和键值都是value。
-
Set.prototype.keys()
:返回键名的遍历器 -
Set.prototype.values()
:返回键值的遍历器 -
Set.prototype.entries()
:返回键值对的遍历器 -
Set.prototype.forEach()
:使用回调函数遍历每个成员
WeakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。
1、WeakSet 的成员只能是对象,而不能是其他类型的值。
const ws = new WeakSet();
ws.add(1)
// TypeError: Invalid value used in weak set
ws.add(Symbol())
// TypeError: invalid value used in weak set
2、WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0
,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。
Map
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
参数
事实上,不仅仅是数组,任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作Map
构造函数的参数。这就是说,Set
和Map
都可以用来生成新的 Map。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.set(o = {a:1},1);
console.log(map.get(o));//同一个引用才能读取
Map实例属性和方法
属性
-
Map.prototype.constructor
:构造函数,默认就是Map
函数。 -
Map.prototype.size
:返回Map
结构的成员总数。
方法
操作方法
-
Map.prototype.set(key, value)
给map实例设置键值对然后返回操作后的map -
Map.prototype.get(key)
根据键获取值,找不到返回undefined -
Map.prototype.has(key)
方法返回一个布尔值,表示键是否存在于此 map 之中。 -
Map.prototype.delete(key)
删除一个键值对,返回boolean -
Map.prototype.clear()
清除所有成员没有返回值
遍历方法
-
Map.prototype.keys()
:返回键名的遍历器。 -
Map.prototype.values()
:返回键值的遍历器。 -
Map.prototype.entries()
:返回所有成员的遍历器。 -
Map.prototype.forEach()
:遍历 Map 的所有成员。
需要特别注意的是,Map 的遍历顺序就是插入顺序。
其他
Map转数组:扩展运算符(...
)
数组转Map:把数组当成Map构造的参数
Map转对象:~
对象转Map:可以通过Object.entries()
Map转JSON:
JSON转Map:
WeakMap
WeakMap
与Map
的区别有两点。
首先,WeakMap
只接受对象作为键名(null
除外),不接受其他类型的值作为键名。
其次,WeakMap
的键名所指向的对象,不计入垃圾回收机制。WeakMap
的设计目的在于,有时我们想在某个对象上面存放一些数据,但是这会形成对于这个对象的引用。
String拓展方法
startWith() & endsWith() 判断字符串是否以参数作为开头/结尾。
let str = "hello ECMAScript"
let r1 = str.startsWith("hello");
let r2 = str.endsWith("script");
console.log(r1,r2);//true false
对象增强写法
let width=100;
let height=50;
let color="red";
const obj={
/*
ES5写法
width:width,
height:height,
color:color,
run:function(){}
*/
/*ES6写法*/
width,
height,
color,
run(){}
}
localStorage和sessionStroage
Web 存储对象 localStorage
和 sessionStorage
允许我们在浏览器上保存键/值对。
它们有趣的是,在页面刷新后(对于 sessionStorage
)甚至浏览器完全重启(对于 localStorage
)后,数据仍然保留在浏览器中。我们很快就会看到。
- sessionStorage关闭页面后消失,刷新不会消失。
- localStorage关闭浏览器也不会消失,需要手动移出。
与cookie的区别:
- cookie会随着请求发送到服务器,storage不会
- storage允许保存更多的信息
- 不同协议或子域无法彼此访问数据。
两个存储对象都提供相同的方法和属性:
-
setItem(key, value)
—— 存储键/值对。 -
getItem(key)
—— 按照键获取值。 -
removeItem(key)
—— 删除键及其对应的值。 -
clear()
—— 删除所有数据。 -
key(index)
—— 获取该索引下的键名。 -
length
—— 存储的内容的长度。
ES6中的类和对象
对象
抽取对象的公共属性和行为封装成一个类,对类进行实例化。获取内的对象。在javascript中对象时一组无需的相关属性和方法的集合,所有事物都是一个对象。
类
ES6可以通过class关键字声明一个类,之后使用这个类来实例化对象。
class Star{
constructor(name,age){
//new的时候自动执行的构造函数
this.name=name;
this.age=age;
console.log("刘华来了");
}
song(song){
console.log(this.name+'来唱'+song);
}
}
const star = new Star("刘华",28);
star.song("忘情水");
类的继承
class Father{
constructor(x,y){
this.x=x;
this.y=y;
}
sum(){
console.log(this.x + this.y);
}
}
class Son extends Father{
constructor(x,y){
super(x,y);
//super必须在this之前调用
//super指向父类,super()代表父类的构造函数
//son的x,y使用父类的的构造方法,但不影响父类的属性
}
}
var father = new Father(5,6);
var son = new Son(1,2);
son.sum();//3
father.sum();//11
this
constructor里面的this指向父类,方法里面的this指向调用者。
ES5的对象
使用构造函数。
function Star(name,age){
this.name=name;
this.age=age;
this.song=function(){
console.log('唱歌');
}
}
var star = new Star('刘德华',35);
star.sex='男';
实例成员:name,age,构造函数的形参,只能通过实例化的对象访问。star.name
静态成员:之后为对象添加的属性,只能通过构造函数访问。Star.sex
构造函数存在的问题:同一个函数开辟了多个内存空间去储存,浪费资源。
解决方法:把共有的函数和属性定义在构造函数的原型上,这些属性和函数为所有对象共享。
this指向问题
1、在构造函数中的this指向对象实例
2、原型对象的函数里面的this指向实例对象
1:this永远指向一个对象;
2:this的指向完全取决于函数调用的位置;
3:this会根据运行环境的改变而改变
this的4个应用场景
1、作为对象属性被调用
2、作为普通函数被调用
3、作为构造函数
4、call和apply的应用
call
调用函数,并且可以改变函数的this指向。
function fn(x,y){
console.log(this);//此this指向window
console.log("奶茶少冰走糖");
console.log(x+y+'嘿嘿嘿');
}
var obj={
name:'andy'
}
fn.call(obj,4,3);//第一个参数使得fn里面的this指向了obj对象,后面的参数时fn的形参
使用call和原型实现继承
function Father(x,y){
this.x=x;
this.y=y;
this.fn=function(){console.log(123);}
}
function Son(x,y){
Father.call(this,x,y);//子构造函数的实例对象可以使用父构造函数的东西了
}
var son = new Son(3,4);
console.log(son.fn);