目录
1.let ,var ,const
let 特点
1.变量不能重复声明
这种是不被允许的
let a = 5
let a = 6
2.块级作用域
存在3种作用域,全局作用域,函数作用域,eval作用域(在ES5的模式下)
什么是块级作用域呢? 是指只在代码块级内产生作用,出了作用域则不起作用
//比如 let 使用这种写法,则会报错
{
let a = 666
}
console.log(a)
//而对于 var 的使用, 则不会报错
{
var a = 2
}
console.log(a)
例如 for 循环
//使用 let 声明则会输出 0~9
for (let i = 0; i < 10; i++) {
console.log(i)
}
//而使用 var 声明则会输出10个10
for (var i = 0; i < 10; i++) {
console.log(i)
}
3.不存在变量提升
变量提升:在代码编译之前就已经声明了变量, 而var 可以存在变量提升
例如这样:
console.log(a);
var a = 999
控制台输出结果是undefined
则相当于在执行前就已经声明了变量 a
var a;
console.log(a);
var a = 999
而 let 不存在变量提升
console.log(a);
let a = 999
控制台则直接发生报错
4.不影响作用域链
函数fun 作用域不存在变量 a ,则向上一级查找变量a = 6
{
let a = 6;
function fun () {
console.log(a)
}
}
cosnt 特点
1. 声明常量一定要赋初值
const A = 6
2. 声明一般使用大写
当然小写也是可以的,但大写规范性更好
3.常量的值不允许改变
即前面已经声明了A = 6, 后面不允许再改变它的值
A = 666
4.块级作用域(见上面解释)
5.对于数组和对象的元素的修改,不算对常量的修改,不会发生报错
//这种修改没有问题
const arr = [1, 2, 3, 4, 5]
arr.push(6)
console.log(arr);
//这种则会报错
const arr = [1, 2, 3, 4, 5]
arr = [1, 2, 3]
为什么呢?
这是因为数组和对象事属于引用类型,它们存储的时候保存的是指针地址,所以说当我们修改里面的元素时并没有改变其指针的地址,所以修改是合法的
2.解构赋值
什么是解构赋值?
它是允许按照一定的模式从数组或者对象中提取值,对变量进行赋值,并且在 js 中使用 [ ], { } 提取其中的值
//数组的解构赋值
const arr = [1, 2, 3, 4, 5]
let [a, b, c, d, e] = arr
console.log(a);
console.log(b);
console.log(c);
//对象的解构赋值
const my = {
name: 'yy',
age: 18,
hobby: function() {
console.log("睡懒觉");
}
}
let {name, age, hobby} = my
console.log(name);
console.log(age);
hobby();
3.模板字符串
模板字符串是增强版的字符串,使用反引号( ` ` )包裹字符串,并且在字符串中可以使用( ${ } )嵌套变量或者表达式
//1.声明
let hobby = `我喜欢睡懒觉`
//2.允许出现换行符
let str = `
<ul>
<li>臭豆腐</li>
<li>臭豆腐2</li>
<li>臭豆腐3</li>
</ul>`;
//3.变量嵌入
let name = `yy`
let my = `我的名字是${name}`
console.log(my);
4.对象的简化写法
在es6中,可以使用更简洁的方式,在大括号中直接去写变量和函数,最为对象的属性和方法,写方法时也可以去掉 :function
let name = 'laoliu'
let age = function () {
console.log('我的年龄是'+18);
}
const my = {
name,
age,
hobby() {
console.log('我喜欢睡大觉');
}
//hobby:function() {
// console.log('我喜欢睡大觉');
//}
}
5.箭头函数
在 es6 中引入了 => 来定义函数,省去了关键字 function 用法如下
//函数的声明
let fn = function() {
console.log('aaa');
}
let fun = (a, b) => {
console.log('bbb');
}
//调用函数
fn()
fun()
1.this 的指向问题
箭头函数中的 this 是静态的, 它始终指向函数声明时所在作用域下的 this 的值
举个栗子~
function fun() {
console.log(this.hobby);
}
const fun2 = ()=> {
console.log(this.hobby);
}
//设置window 对象的 hobby 属性
window.hobby = '睡大觉'
const my = {
hobby: '吃螺蛳粉'
}
//直接调用
fun()
fun2()
//call 函数主要改变 this 的指向对象
fun.call(my)
fun2.call(my)
我们首先声明好函数和属性,然后直接调用函数,打印发现他们的 this 指向都是 window ,然后再利用call 函数改变两个函数的 this 的指向,打印发现 fun1 的 this 指向了 my , 而 fun2 的 this 依然指向的是 window
2.不能作为构造函数实例化对象
这种写法是错误的,控制台报 “Per is not a constructor” 错误
let Per = (name, age) => {
this.name = name;
this.age = age;
}
let my = new Per('yy', '18')
console.log(my);
3.不能使用 arguments 变量
//错误使用,控制台报错 arguments 未定义
let fn = () => {
console.log(arguments);
}
fn();
4.箭头函数的简写
(1) 省略小括号
当形参只有一个时
let fn = n => {
return n++;
}
(2) 省略花括号
当代码体只有一条语句时,可以省略花括号,并且需要省略 return ,其中语句的执行结果就是函数的返回值
let fn = (n) => {
return n++;
}
//简写形式
let fn = (n) => n++:
总结一下~
箭头函数适合与 this 无关的回调,比如定时器,数组方法的回调,不适合与 this 有关的回调,比如事件和对象的方法
6.函数默认参数值
在es6中允许给默认函数参数初始值
栗子~
1.形参默认初始值,具有默认的参数,一般要靠后写
//如果我们给a, b, c 都赋予值, 则参数c为输入的值
function fun(a, b, c = 6) {
return a + b + c;
}
console.log(fun(1, 2, 3));
//如果我们没有给 c赋予值,则c 默认值是6
function fun(a, b, c = 6) {
return a + b + c;
}
console.log(fun(1, 2, 3));
//这种输入是不合理的,1和2并不会直接给参数a, b 赋上值,
//而是会直接把 c 的值覆盖掉,控制台的输出结果为NaN
function fun(a, c = 6, b) {
return a + b + c;
}
console.log(fun(1, 2));
2.还可以与解构赋值结合
//如果不使用这种方法,就会写多个param,比较麻烦
function connect(param) {
console.log(param.host);
console.log(param.username);
console.log(param.password);
console.log(param.port);
}
//而这种与解构赋值结合的方法方便很多
function connect({host, username, password, port}) {
console.log(host);
console.log(username);
console.log(password);
console.log(port);
}
//当然也可以采用默认值的方式,如果host 不输入则采用参数的默认值
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
})
7. rest 参数
在es6 中引入了 rest 参数,用于获取函数的实参,用来代替 arguments
那我们先来简单了解一下arguments 参数~
arguments 是一种类数组对象,代表传给参数的 function 列表,它包含 length 属性来获取传入参数的个数,而其他数组有的方法arguments 都没有,所以为了使用数组的方法,必须使用 Array.prototype.slice.call
先将其转为数组
function fun() {
console.log(arguments);
}
fun('熊大', '熊二')
arguments 控制台输出的是一个对象
对于 rest 参数就有很大的优势了
先来解释下rest 参数,它是用于获取多余的参数,rest 参数对应的是数组,该变量将多余的参数放在数组中。
求几个数的和:
function fun(...args) {
let sum = 0;
for( var e of args) {
sum+=e
}
return sum;
}
console.log(fun(1, 2, 3));
对于resr 参数特别需要注意:...argu 必须放到最后面
function fun(a, b, ...argu) {
console.log(a);
console.log(b);
console.log(...argu);
}
fun(1, 2, 3, 4, 5, 6)
控制台输出的结果是1, 2, 3456,也就是1给了a, 2给了b, 3456给了...argu ,如果改变参数的顺序就会混乱
8.扩展运算符
什么是扩展运算符呢?
扩展运算符(...),是es6的新语法,可以将数组转化为丢逗号分隔的参数序列
举个栗子~
//这种方式打印出来的是一个值,也就是输入的数组
const arr = ['a', 'b', 'c']
function fun() {
console.log(arguments);
}
fun(arr)
//而使用拓展运算符的形式打印出来的是三个值a, b, c
const arr = ['a', 'b', 'c']
function fun() {
console.log(arguments);
}
fun(...arr)
那我们可以怎样使用呢?
1.数组的合并
const arr1 = ['a', 'b', 'c']
const arr2 = [1, 2, 3]
const arr3 = [...arr1, ...arr2] //arr3就是合并后的数组
console.log(arr3);
2.数组的克隆
const arr1 = ['a', 'b', 'c']
const arr4 = [...arr1] //克隆后的数组
console.log(arr4);
3.将伪数组转化为真正的数组
伪数组:可以理解为类似数组的集合,他们和数组一样有索引和length 但是没有一些数组特有的方法,比如arguments,DOM的children 元素
举个栗子~
const divs = document.querySelectorAll('div'); //获取div 数组
const divArr = [...divs]; //转化为真正的数组
console.log(divArr);
9.Symbol 数据类型
在es6中引入了一种新的原始数据类型Symbol ,表示独一无二的值,是JavaScript 语言的第七种数据类型,类似于字符串的数据类型。
Symbol 的几个特点:
(1) Symbol 的值是唯一的,用来解决命名冲突的问题
(2)不能与其他数据进行运算
(3)Symbol 定义的对象属性不能使用 for...in 循环遍历,但是可以使用 Reflect.ownkeys 来获取对象的所有键名
let sym = Symbol() //创建Symbol
let res = sym + 100
console.log(res);
9.迭代器
迭代器(Iterator)是一种接口, 为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator接口,就可以完成遍历操作。
在es6中创造了一种新的遍历命令 for...of 循环,Iterator 接口主要提供for...of
原生具有 Iterator 接口的数据(可以使用for ... of 遍历):Array, Arguments, Set, Map, String, TypedArray, NodeList
那么迭代器是如何工作的呢?
首先创建一个指针对象,指向当前数据结构的其实位置,第一次调用对象的next 方法,指针自动指向数据结构的第一个成员,接下来不断地调用 next 方法,指针一直往后移动,直到指向最后一个成员,每调用 next 方法就会返回一个包含 value 和 done 属性的对象。
- value 表示可迭代对象的下一个值
- done 表示的是是否已经全部取出所有的数据,false表示的是还有数据未取出,true 表示的是已经全部取出shun
let arr = ['阿呆1号', '阿呆2号', '阿呆3号', '阿呆4号']
let iterator = arr[Symbol.iterator]() //生成迭代器
console.log(iterator.next()); //输出 done:false value:'阿呆1号'
console.log(iterator.next()); //输出 done:false value:'阿呆2号'
console.log(iterator.next()); //输出 done:false value:'阿呆3号'
console.log(iterator.next()); //输出 done:false value:'阿呆4号'
console.log(iterator.next()); //输出 done:true value:undefined
再来说一说for...in 和 for ... of 的区别:
- 区别一:都可以遍历数组,但是for...in 输出的是数组的下标,for...of 输出的是数组的值
const arr = ['a', 'b', 'c', 'd', 'e']
for (const key in arr) {
console.log(key); //输出的是0,1,2,3,4
console.log(arr[key]); //输出的是a, b, c, d, e
}
for (const iterator of arr) {
console.log(iterator); //输出的是a, b, c, d, e
}
- 区别二:for ... in 可以遍历对象,而 for ... of 不可以遍历对象,他只能够遍历带有迭代器的,比如Array, Set, Map...
const my = {
name: 'yy',
age: 18,
hobby: '睡懒觉'
}
for (const key in my) {
console.log(my[key]); //输出:yy, 18,睡懒觉
}
for (const iterator of my) {
console.log(my); //输出报错信息: my is not iterable
}
遍历数组对象:
可通过for ... in 和 for ... of 结合的形式遍历数组对象
const arr =[
{
name: '小花',
age: 19,
hobby: '打游戏'
},
{
name: '小绿',
age: 20,
hobby: '睡觉'
},
{
name: '阿紫',
age: 18,
hobby: '摆烂'
}
]
for (const iterator of arr) {
for (const key in iterator) {
console.log(iterator[key]); //输出全部人的信息
}
}
10.生成器
生成器函数是es6 提供的一种异步编程解决方案,语法与传统的函数完全不同。
(1)生成器的声明与调用
//声明
function * fun () {
console.log('熬大夜学编程');
}
//执行
let iterator = fun();
//返回的结果
//console.log(iterator); //输出的其实是一个迭代器对象,里面有next方法
iterator.next(); //不写这一步不会再控制台打印出结果
生成器函数还可以引入yield 语句,通过next 方法来控制代码的一个向下的执行
function * fun() {
console.log(111);
yield '分隔1';
console.log(222);
yield '分隔2';
console.log(333);
yield '分隔3';
console.log(444);
}
let iterator = fun();
iterator.next(); //输出111
iterator.next(); //输出111 222
iterator.next(); //输出111 222 333
iterator.next(); //输出111 222 333 444
(2)生成器的函数参数
next 语句也可以传递参数,传递的参数作为上一个yield 语句的返回结果,效果如下:
function * fun(arg) {
console.log(arg);
let first = yield '分隔1';
console.log(first);
let second = yield '分隔2';
console.log(second);
let third = yield '分隔3';
console.log(third);
}
let iterator = fun('a');
console.log(iterator.next());
console.log(iterator.next('b')); //传入参数b,则first为b
console.log(iterator.next('c')); //传入参数c,则second为c
console.log(iterator.next('d')); //传入参数d,则third为d