1:const,let,var
var声明变量存在变量提升,而let和const不存在变量提升
console.log(a); //undefined 在声明前进行控制台输出 可以输出 但是输出的是undefined
var a = '张三';
console.log(a); //张三 在声明之后进行控制台输出 可以输出结果
//而用const和let声明变量时,无法进行变量提升,此事会直接报错
console.log(b);
const b='李四';
console.log(c);
let c='王五';
function fn() {
//var a
if (true) {
console.log(a + ' now')
}
else {
var a = 1
console.log(2)
}
}
fn() // a -> undefined 输出结果为undefined now var a被变量提升到了if之前 但是提升的仅仅是 var a 而不是 var a=1 因此在if语句中打印的是undefined +now
let和const都是块级局部变量(只在当前代码块当中起作用)
{
let/const a=1;
}
console.log(a); //都会显示a is not defined
而const和let的特性一样,不同的是
- const声明的时候要先赋值
- const只能进行一次赋值,赋值之后不能改变
- 如果声明的是复合类型数据,可以修改其属性
- let 和 const 声明只在最靠近的一个块中(花括号内)有效
同一作用域下let和const不能声明同名变量,而var可以
const a = 2
const a = 1 //Identifier 'a' has already been declared 标识符“a”已声明
面试题
for (let i = 0; i < 5; i++) {
console.log(i)
} //打印的是0,1,2,3,4
参考:
2:模板字符串
学习ES6之前,在处理字符串的时候往往通过“\”和“+”进行拼接字符串
$("body").html("This demonstrates the output of HTML \
content to the page, including student's\
" + name + ", " + seatNumber + ", " + sex + " and so on.");
而ES6中
- 基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}来界定;
- ES6反引号(``)直接搞定;
//ES6引入新的声明字符串方式 ``
// 1.声明
let str=`我是叶念`;
console.log(str,typeof str);
// 2.内容中可以直接出现换行符
// 3.直接进行变量的拼接
let love='学习';
let my=`${love}是我的最爱`;
console.log(my); //会直接显示“学习是我的最爱”
同时对于模板字符串需要注意的是: 模板字符串中的换行和空格都是会被保留的 如下所示:
innerHtml = `<ul>
<li>menu</li> <li>mine</li>
</ul>
`;
console.log(innerHtml); 因为两个li没有分行 且li之间有空格 因此控制台输出的结果为:
<ul>
<li>menu</li> <li>mine</li>
</ul>
标签模板
标签模板,是一个函数的调用,其中调用的参数是模板字符串。
alert`Hello world!`;
// 等价于
alert('Hello world!');
3:常用运算符
ES6中常用的有扩展、剩余运算符,使用“...”,后面跟着一个含有iterator接口的数据结构
扩展运算符
以数组为例,使用扩展运算符使得可以"展开"这个数组,可以这么理解,数组是存放元素集合的一个容器,而使用扩展运算符可以将这个容器拆开,这样就只剩下元素集合,你可以把这些元素集合放到另外一个数组里面
- 扩展运算符将数组转换为用逗号分割开的参数序列
// 扩展运算符将数组转换为逗号分割的参数序列
// 声明一个数组
const boy=['张三','李四','王五'];
// 声明一个函数
function shuchu(){
console.log(arguments);
}
console.log(...boy); //在控制台输出 张三 李四 王五
- 扩展运算符也可以用作数组的合并
// 数组的合并
const arr1=[1,2,3];
const arr2=[4,5,6];
// const a1=arr1.concat(arr2);<==>
const a1=[...arr1,...arr2]
console.log(a1); //在控制台输出 [1,2,3,4,5,6]
- 扩展运算符用于数组的克隆
// 数组的克隆
const bgm=['e','g','m'];
const bg=[...bgm];
console.log(bg); //在控制台输出 ["e", "g", "m"]
- 扩展运算符将伪数组转换为真正的数组
<div></div>
<div></div>
<div></div>
<script>
/*利用扩展运算符将伪数组转成真数组*/
var oDivs= document.getElementsByTagName('div');
console.log(oDivs)
console.log( oDivs instanceof Array) //判断是不是真数组
let arr =[...oDivs];
console.log(arr)
console.log(arr instanceof Array)
</script>
使用扩展运算符可以快速的将类数组转为一个真正的数组,合并多个数组,克隆数组和将伪数组转换为真数组
剩余运算符
剩余运算符最重要的一个特点就是替代了以前的arguments 访问函数的arguments对象是一个很昂贵的操作,以前的arguments.callee,arguments.caller都被废止了,建议在支持ES6语法的环境下不要在使用arguments对象,使用剩余运算符替代(箭头函数没有arguments,必须使用剩余运算符才能访问参数集合)。
function func(a,b,c){
console.log(arguments[0],arguments[1],arguments[2]);
}
func(1,2,3)
//rest是形参,承载了所有的函数参数,可以随意取名
function func1(...rest){
console.log(rest);
}
func1(1,2,3)
剩余运算符可以和数组的解构赋值一起使用,但是必须放在最后一个,因为剩余运算符的原理其实是利用了数组的迭代器,它会消耗3个点后面的数组的所有迭代器,读取所有迭代器生成对象的value属性,剩运算符后不能在有解构赋值,因为剩余运算符已经消耗了所有迭代器,而数组的解构赋值也是消耗迭代器,但是这个时候已经没有迭代器了,所以会报错。 剩余运算符和扩展运算符的区别就是,剩余运算符会收集这些集合,放到右边的数组中,扩展运算符是将右边的数组拆分成元素的集合,它们是相反的。
4:箭头函数
在ES6中,箭头函数就是函数的一种简写形式,通过“=>”来定义函数
箭头函数最直观的三个特点
- 不需要function关键字来创建函数
- 省略return关键字
- 继承当前上下文的this关键字
//省略小括号 当形参只有一个的时候
let add=n=>{
return n+n;
}
console.log(add(1));
//省略花括号 当代码题只有一条语句的时候
let pow=(n)=>n*n;
console.log(pow(2));
细节:当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{} 和 return;
箭头函数对于使用function关键字创建的函数有以下区别
- 箭头函数没有arguments(建议使用更好的语法,剩余运算符替代)
// 不能使用arguments变量
let fn=()=>{
console.log(arguements);
}
fn(1,2,3); //arguements is not defined
- 箭头函数没有prototype属性,不能用作构造函数(不能用new关键字调用)
- 箭头函数没有自己this,它的this是词法的,引用的是上下文的this,即在你写这行代码的时候就箭头函数的this就已经和外层执行上下文的this绑定了(这里个人认为并不代表完全是静态的,因为外层的上下文仍是动态的可以使用call,apply,bind修改,这里只是说明了箭头函数的this始终等于它上层上下文中的this)
// 箭头函数的this是静态的 this始终指向函数声明时所在作用域下的this的值 call,apply,bind无法改变this指向
function getname(){
console.log(this.name);
}
let getname2=()=>{
console.log(this.name);
}
window.name="张三";
const names={
name:"李四"
}
// 直接调用
// getname(); //张三
// getname2(); //张三
// 采用call方法更改this指向
getname.call(names); //李四
getname2.call(names); //张三..
因为setTimeout会将一个匿名的回调函数推入异步队列,而回调函数是具有全局性的,即在非严格模式下this会指向window,就会存在丢失变量a的问题,而如果使用箭头函数,在书写的时候就已经确定它的this等于它的上下文(这里是makeRequest的函数执行上下文,相当于将箭头函数中的this绑定了makeRequest函数执行上下文中的this)因为是controller对象调用的makeRequest函数,所以this就指向了controller对象中的a变量
// 从数组中返回偶数的元素
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
const result = arr.filter(item => item % 2 === 0);
console.log(result);
<style>
div {
width: 200px;
height: 200px;
background: red;
}
</style>
</head>
<body>
<div id="ad">
</div>
<script>
// 箭头函数适合与this无关的毁掉,定时器、数组的方法回调
// 箭头函数不适合与this有关的回调 事件回调,对象的方法
// 点击div 2s之后颜色改变
// 获取元素
let ad = document.getElementById('ad');
// 绑定事件
ad.addEventListener("click", function () {
// 保存this的值
// let _this=this;
// setTimeout(function(){
// // 修改背景颜色 用this来修改
// _this.style.background='pink'
// },2000)<===>
setTimeout(() => {
this.style.background = 'pink';
}, 2000)
// 箭头函数this是静态的指向在声明时所在作用域下的this指向
})
</script>
</body>
注意
箭头函数替代了以前需要显式的声明一个变量保存this的操作,使得代码更加的简洁
箭头函数的this指向即使使用call,apply,bind也无法改变
不要在可能改变this指向的函数中使用箭头函数,类似Vue中的methods,computed中的方法,生命周期函数,Vue将这些函数的this绑定了当前组件的vm实例,如果使用箭头函数会强行改变this,因为箭头函数优先级最高(无法再使用call,apply,bind改变指向)
全文参考: