1. let && const
let命令和var一样用于声明变量,但是不同的是let的作用域为局部作用域,且let声明的变量不会出现像var那样存在“变量提升”的现象,且let声明的变量不可重复。
{
let a = 110;
var b = 120;
}
console.log(b);//b =120
console.log(a);//a is not defined
复制代码
在函数外部可以获取到b,获取不到a,因此let适合在for循环计数器中用。
注意事项:
let不能重复声明
let不允许在相同作用域内重复声明同一个变量,即同一个作用域内不允许出现名称相同的变量。
let a = 1;
var a = 2;
//像这样声明会报错:Uncaught SyntaxError: Identifier 'a' has already been declared
复制代码
var a = 1;
let a = 2;
//像这样声明也会报错:Uncaught SyntaxError: Identifier 'a' has already been declared
复制代码
let的死区现象
let a = 110;
if(true){
console.log(a);
let a = 120;
console.log(a);
}
//代码在第一次输出a 的时候会报错,提示a 没有定义,这就是死区效应。原因是:let不像var一样存在“变量提升现象”,所以一定要在声明后使用,否则将会报错。
复制代码
const用于声明一个常量,一旦声明,必须立即赋值,且声明后值将不会再改变。
const a;//会报错,没有立即赋值
复制代码
const PI = 3.14159;
PI // 3.14159
PI = 110;//报错,常量不能被重新赋值。
复制代码
2.箭头函数
() => 1;
//这是一个自执行的匿名函数。等于如下代码:
(function(){
return 1;
})
复制代码
//可以传参数:
(a) => 1 + a;
//相当于
(function(a){
return 1 + a;
})
复制代码
注意:箭头函数可以说是函数的缩写,但并非完全相同,箭头函数没有constructor,没有prototype,没有this,所以>不支持new操作符,不能当做构造函数。但是箭头函数对于this的处理和其他函数不一样。箭头函数中的this始终指向函数定义时的this,而非执行的时候。也就是说箭头函数执行时,会向外层函数查找this,直到找到this就拿来为己用!
3. 模板字符串
格式为
${}
;大括号里可以放任意的js表达式,可以进行运算,以及引用对象属性。
传统字符串的使用:
var name = '旺财';
var age = 22;
var java = function(name,age){
var my = '我的名字是:'+ name +'\n' +
'我今年' + age + '岁了';
return my;
}
复制代码
而现在:
//可多行
var java = `我的名字是:${name}
我今年${age}岁了`;
复制代码
模板字符串是增强版的字符串,用反引号(``)标识
var a = 110;
var b = 120;
`${a} + ${b} = &{a+b}`//"110 + 120 = 230"
复制代码
也可在字符串中嵌入变量:
let name = "老仙女",time = "today";
`Hello ${name},今天是${time}耶!`
复制代码
模板字符串可以多行书写,模板字符串中的所有空格,新行,缩进都会原样输出在生成的字符串中。如果不想要空格换行,可以使用trim方法消除。 trim 去除字符串空格.
trim 左右空格都去掉 trimLeft 去掉左空格 trimRight 去掉右空格 使用如下:
var str = " a b c ";
console.log(str);//" a b c "
console.log(str.trim());//"a b c"
console.log(str.trimLeft());//"a b c "
console.log(str.trimRight());//" a b c"
复制代码
repeat:构造并返回一个新的字符串,该字符串包含被连接在一起的指定数量的字符串的副本。还是看例子吧:
var str = "12345";
console.log(str.repeat(5));//里面的5,是指重复的遍数
//1234512345123451234512345 这是一个新的字符串里面有5遍的12345
复制代码
includes 用来判断一个数组中是否包含一个指定的值,根据市局情况,如果包含返回true,否则返回false。如下:
var arr = [1,2,3,4,5]
console.log(arr.includes(1))//true
console.log(arr.includes(6))//false
//字符串中也可用
var str = "a bc def";
console.log(str.includes("a"))//true
console.log(str.includes("a b"))//true
console.log(str.includes("bc" ))//true
console.log(str.includes("abc"))//false
复制代码
padStrat padEnd 在开始(padStrat )/结尾(padEnd)部位填充
var a = "hello";
a.padStart(10,"*")//"*****hello"
//第一个参数规定了字符串的长度,padstart就是确保字符串中的长度为n(10),若本身达不到这个长度便用第二个参数中的字符填充至n个长度。如果n<本身的长度那么输出的就是原字符串,不做改变。
var b = "hi";
b.padEnd(10,"*")//"hi********"
复制代码
4. 扩展运算符
扩展运算符就是三个点(...).它将一个数组转为用逗号分隔的参数序列。
var arr = ["a","b","c"];
var arr1 = [...arr];
console.log(arr1)//a, b, c
复制代码
[...arr]的作用就是把arr这个数组作为参数直接传入arr1中展开。
扩展运算符与正常的函数参数可以结合使用,非常灵活。
var arr = [1,2,3];
var arr1 = [4,5,6,...arr]
复制代码
var arr = [...(a>b?[ok]:[goout]),'c'];
//这样也是OK的
[...[],1];
//如果扩展运算符后面是一个空数组,则不产生任何效果。
复制代码
扩展运算符还有一个比较常用的功能是,连接两个数组。
var arr1 = [1,2,3];
var arr2 = [4,5,6];
arr1.push(...arr2);
复制代码
扩展运算符还可以将字符串转为真正的数组。
[..."hello"]
//["h","e","l","l","o"];
复制代码
//arguments对象
function f(){
let as = [...arguments];
//NodeList对象
[...document.querySelectorAll("li")];
}
复制代码
5. Class(类)
前面我们都是创建构造器,然后去new构造器,构造器就相当于一个类,在ES6中,就可以使用class来创建对象了。从形式上,向主流的面向对象的语言靠拢。
注意事项:
- class 是关键字,后面紧跟类名,类名首字母大写,采取的是大驼峰命名法则。类名之后是{}。
- 在{}中,不能直接写语句,只能写方法,方法不需要使用关键字
- 方法和方法之间没有逗号。不是键值对
使用class来声明一个类,如下:
class New{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(`我是${this.name},今年${this.age}岁了`)
}
}
var p1 = new New("小仙女","22");
console.log(p1.say());
//输出我是小仙女,今年22岁了
复制代码
可以说使用class是相当给力的
6. 变量的结构赋值
ES6中允许按照一定的模式,从数组和对象中提取值,对变量进行赋值。更加便利的去声明变量。
1. 数组的解构赋值
数组的解构赋值需要按照对应位置,对变量进行赋值。这种写法属于“模式匹配”,只要等是两边的模式相同,左边的变量就会被赋予对应的值。如下:
let [a,[b],c] = [1,[2],3];
a//1
b//2
c//3
let[ e, ,d] = ["hi","hello","gun"];
e//hi
d//gun
let[hh,...haha] = [1,2,3,4];
hh//1
haha//[2,3,4]
let [a] = [];//解构不成功,a的值就是undifined
let [b,a] = [1];// b//1 a的值是undifined
let [a,b] = [1,2,3,4,5,6];//这种情况是不完全解构,对应的值是对应位置的值。
a//1
b//b
let [a] = 1;//如果等号两边模式不相同,会报错。
复制代码
解构赋值允许指定默认值。注意,ES6内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undifined,默认值才会生效。如下:
let [a = 110] = [undifined]// a//1
let [a = 110] = [null]// a//null
复制代码
如果默认值是一个表达式,那这个表达式是惰性求值的,即只有在用到的时候,才会求值。如下:
function f(){
console.log('aaa');
}
let [x = f()] = [1];
//此时x有值,是1,所以函数f根本不会执行。等价于下面的代码:
let x;
if([1][0] === undefined){
x = f();
}else{
x = [1][0];
}
复制代码
2. 对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量名必须与属性名一致,才能取到正确的值。
let {a,b} = {a:"hello",b:"hi"}
a//hello b//hi
let {c} = {a:"hello",b:"hi"}
c//undefined
复制代码
如果想变量名与属性名不一样,必须写成下面这样:
let obj = {a:'hello',b:'hi'};
let { a:c, b:d } = obj;
c//hello d//hi
复制代码
这实际说明,对象的解构赋值是下面形式的简写。
let { a:b, c:d } = { a:"hello",c:"hi"};
复制代码
就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。对象的解构也可以指定默认值(略)。
7. Array.from
Array.from方法用于将两类对象转为真正的数组:类似数组的对象和可遍历的对象。
实例1
var arrLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
};
var arr1 = Array.form(arrLike);
复制代码
实例2
var sts = document.getElementById("st");
console.log(Array.isArray(Array.from(sts)));
//true;
复制代码
实例3
//arguments对象
function f(){
var str = Array.from(arguments);
}
复制代码
Array.from的另一个应用是,将字符串转为数组,然后返回字符串的长度。
function countSymbols(string){
return Array.form(string).length;
}
复制代码
Array..of方法用于将一组值,转换为数组。
Array.of(2,34,45)//[2,34,45]
Array.of(2,34,45).length//3
复制代码
8. Map && Set
Set
ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。set不是数组,它是一个像对象的伪数组:
var s1 = new Set();
s1.add(1)
s1.add(2)
console.log(Array.isArray(s1))
//false //说明set不是数组。
复制代码
var ss = new Set();
[1,12,3,4,3,1,12,3].forEach(x => s.add(x));
for(let i of s){
console.log(i);
//1 12 3 4
//上面的代码通过add方法向Set结构加入成员,结果表明Set结构不会添加重复的值。
}
复制代码
Set函数可以接受一个数组(或者具有interable 接口的其他数据结构)作为参数,用来初始化。
//例一
let set = new Set([1,2,3,3,3]);
[...set]//[1,2,3]
//例二
let item = new Set([1,2,3,3,3]);
item.size //3
//例三
var set = new Set(document.querySelectorAll('div'));
set.size
复制代码
//去掉数组的重复成员
[...new Set(array)]
复制代码
向Set加入值的时候,不会发生类型转换,所以1和“1”是两个不同的值。Set内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要区别是NaN等于自身,二=而精确相等运算符认为NaN不等于自身。
Set结构的实例有一下属性。 -Set.prototype.constructor:构造函数,默认就是Set函数。 -Set.prototype.size:返回Set实例的成员总数。 Set实例的符分为两大类:操作方法和遍历方法。 四个操作方法
1. -add(value):添加某个值,返回Set结构本身。
2.-delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
3.-has(value):返回一个布尔值,表示该值是否为Set的成员。
4.-clear():清除所有成员,没有返回值。
复制代码
s.add(1).add(2).add(2)
s.size//2 因为2被添加了两次
s.has(1)//true
s.has(2)//true
s.has(3)//false 因为s中没有3这个实例
s.delete(2);
s.has(2)//false 此时2这个实例已经被删除掉了。
复制代码
Array.from方法可以将Set结构转为数组。
var item = Set([1,23,4,5]);
var array = Array.from(items);
//这就提供了去除数组重复的另一种方法。
function f(array){
return Array.from(new Set(array));
}
f([1,2,3,4,5,6,5,4,3,2,1])//[1,2,3,4,5,6]
复制代码
Set的四个遍历方法
1. -keys():返回键名的遍历器。
2. -values():返回键值的遍历器。
3. -entries():返回键值对的遍历器。
4. -forEach():使用回调函数遍历每个成员。
复制代码
注意:
Set的遍历顺序就是插入顺序。这个特性有时候非常有用,比如使用Set保存一个回调函数列表,调用的时候就能保证按照添加顺序调用。 keys方法,values方法,entries方法返回的都是遍历器对象。由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
let set = new Set(['a','b','c']);
for(let i of set.keys()){
console.log(i);
}//a b c
for(let i of set.values()){
console.log(i);
}//a b c
for(let i of set.entries()){
console.log(i);
}//['a':'a']// ['b':'b']//['c':'c']
复制代码
Set结构的实例默认可遍历,他的默认遍历器生成函数就是他的values方法。
Set.prototype[Symbol.inerator]===Set.prototype.values
//true
复制代码
所以,可以省略values方法,直接用for..of循环遍历Set。
let set = new Set(['a','b','c','d']);
for(let i of set){
console.log(i);//a b c d
}
复制代码
Set结构的实例与数组一样,也拥有forEach方法,用于对每个成员执行某种操作,没有返回值。
let set = new Set([1,4,7]);
set.forEach((value, key) => console.log(key + ':' + value));
// 1:1 4:4 7:7
复制代码
遍历的应用
扩展运算符(...)内部使用for..of循环,所以也可以用于Set结构。
let set = new Set(['a','b','c']);
let arr = [...set];
//['a','b','c']
复制代码
扩展运算符和Set结构相结合,就可以去除数组的重复成员。
let arr = [3,4,5,3,2,3];
let sa = [...new Set(arr)];
//[3,4,5,2]
复制代码
Map
JavaScript的对象(Object),本质上是键值对的集合,但是传统上只能用字符串当做键。这给它的使用带来了很大的限制。为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,如果使用map,它里面的键可以是任意值。 如何创建map?如下:
var m = new Map([
[1,"hello"],//里面存放的键值对,1 是键,“hello”是指。
["a","123"],
[true,"abc"],
[[1,2,3],{name:"wangcai"}]//可以存放任意值
]);
//注意书写格式,一不小心就会写错哟~
复制代码
使用set进行添加,如下:
var m = new Map([
[1,"hello"],
["abc",true]
]);
//通过set往集合中放入新的值
m.set(false,"abc")
m.set([1,2,3],{name:"wangcai"})
复制代码
还可以去获取,通过get(键),如下:
//get(键名),得到键值
m.get(1)
"hello"
m.get("abc")
true
复制代码
但是get([1,2,3])是获取不到值,如下:
m.get([1,2,3])
undefined
//原因是:get()时要比较栈区中的地址,而不是堆区中的数据。
复制代码
解决如下:
var m = new Map();
m.set(true,"hello")
let a = [1,2,3]//a保存的是[1,2,3]在堆中的地址。
m.set(a,{name:"wangcai"})
m.get(a);//{name:wangcai}
复制代码
重复的键会被覆盖掉,如下:
var m = new Map();
m.set(1,"hi")
m.set(1,"hello")
console.log(m)//Map(1) {1 => "hello"}
// 如果有重复的值,后面的会把前面的覆盖掉。
复制代码
9. 严格模式
之前学习的JS,语法非常灵活,JS中这个灵活的特性,弊大于先利。后来增加了严格模式。使用严格模式的目的:规则,提高编译效率
- 在严格模式下不能使用没有var的变量
"use strict"
a = 110;
//会报错 a is not defined
复制代码
- 在严格模式下不能8进制的数字
"use strict"
var a = 01;
//会报错 Octal literals are not allowed in strict mode
复制代码
- 在严格模式下不能把函数定义在if语句中
"use strict"
if(true){
function f(){
console.log("......")
}
f();
}// 会报错 f is not defined
复制代码
- 在严格模式下函数不能有重名的形参
"use strict"
function f(a,a){
console.log("......")
}
f();// 会报错 Duplicate parameter name not allowed in this context
复制代码
- 在严格模式下arguments不再跟踪形参的变化
"use strict"
function f(a,b){
console.log(a,b) // a//1 b//2
console.log(arguments[0],arguments[1]) // a//1 b//2
arguments[0] = 1111;
arguments[1] = 2222;
console.log(a,b) // a//1 b//2
console.log(arguments[0],arguments[1]) // a//1111 b//2222
}
f(1,2);
复制代码
- 在严格模式下function中的this就不再是window
"use strict"
function f(){
console.log(this)
}
f();//undefided
复制代码
在严格模式下,全局的变量和函数还是属于window的。
"use strict"
var a = 110;
console.log(window.a) //110
function f(){
console.log("...")
}
window.f(); //...
复制代码
严格模式也是有作用域范围的。分整个代码段和函数内。
由一个永远18岁的小仙女编写,欢迎指正~~