非严格模式下,重复声明变量不会出错
var a = 5;
var a = 10;
在ES6中新提供了两种方案,let和const来定义变量。
这两个方法声明的变量都不允许重复
let a = 10;
let a = 5;
//报错 Uncaught SyntaxError: Identifier 'a' has already been declared
ES6之前,定义的变量都是可以更改的,想要声明一个常量,不允许修改,只能通过全部大写来人为的表示一下
var GIT_HOST = "这是一个常量";
但这样的定义,还是不安全。
ES6新添加的const就是声明常量用的
const MIX = 10;
MIX = 5;
//TypeError: Assignment to constant variable.
修改const声明的常量时会报错
一个变量在被定义时,产生执行期上下文(注意是定义时产生)
使用ES5中的var定义的变量,如果是在函数中,它在函数以外的地方是不可见的
但是,如果该变量是定义在{}、if或者for这样的代码块中,它在代码块之外是可见的,相当于全局的变量
var arr = [];
for(var i = 0;i < 3; i++){ //for是一个块级
function b(){ //b方法的定义本质属于全局的,作用域链上只含有全局作用域
console.log(i);
}
arr[i] = b;
}
arr[0](); //3
console.log(i); //3 这里的i是属于全局的
b(); //3
块级定义的内容都属于全局,所以外部访问相当于全局访问
而arr[0]() 调用的是b方法,此时b的作用域链如下 [[scope]] --> scope chain --> { 0 : AO(b自己的) , 1 : GO(全局的) }
b在全局中找到的i是循环结束后的,所以打印的i为3。
在ES6中给出了块级作用域的概念
使用 let 和 const 的定义的变量,多了一个块级的作用域,从外部是无法访问该变量的 。
但是要注意块级中定义的其他内容,本质上只是多了一层块级作用域
var arr = [];
for(let i = 0;i < 3; i++){ //for是块级作用域
function b(){
console.log(i);
}
arr[i] = b;
}
arr[0](); //0
//如果执行 console.log(i); //i is not defined 在全局中已经找不到i了
b(); //返回2
使用let后有两个变化:
1.通过let定义的i值,是专属于for这个块级的,外界无法访问。
2.块级中定义的其他函数,在作用域链上都添加了块级的作用域。
这里的arr[0]() 存的是第一次循环的b方法,其作用域链包括for第一次循环的块级作用域和全局作用域,不再只有全局作用域了
而b方法,在定义时本质上还是属于全局的,只是多了一个块级作用域。
每次循环定义出来的方法b,都会覆盖上一个b,同理作用域链也跟着改变了。
所以循环了三次之后,第三次的b方法,覆盖了前两次,此时b的作用域链包括了最后一次块级作用域和全局作用域
笔记补充:{ }就是一个代码块
{ //块级中定义变量,var可以被外界访问,而let不可以
var a = 10;
let b = 10;
}
console.log(a);
console.log(b); //报错
解构赋值主要用在请求接口时使用
var json = {
"a" : 12,
"b" : 34
};
let {a,b} = json;
用如上方法可以得到a = 12,b=34
相当于一次定义了两个值a,b,并给a,b赋值了
var arr = [12,5,8];
let [a,b,c] = arr;
同理,一次定义三个值a,b,c,并进行赋值
写解构赋值的时候要注意的要求:
1.两边的结构得一样,对象对应对象 – 数组对应数组
2.右边的内容,得有实际的东西,不能啥也不是
3.赋值和解构同时完成
针对第三点看以下代码,不可分开进行
let {a,b}; 报错
{a,b} = {a:12,b:13} //两步应该同时完成
4.在结构赋值时,针对对象进行结构,对象的属性可以有双引号,也可以没有
var json = {
"a" : 12,
"b" : 34
};
let {a,b} = json;
var obj = {
a : 12,
b : 34
}
let {a,b} = obj;
这两个定义出来的a,b没有差别
正常函数:function (){
}
箭头函数:()=>{}
1.如果有且仅有一个参数,这个**()可以不写
2.有且仅有一句语句是return,这个{}和return**可以不写
例子1:
//function add(n){
// return n+5;
//}
function show(n,fn){
console.log(fn(n));
}
//可以把add函数省略
show(12,n=>n+5); //n => n+5就是一个函数,参数是n,返回值n+5
例子2:
let arr = [3,10,56,9];
arr.sort();
console.log(arr); //按照数字第一位的编码进行排序
// arr.sort(function(a,b){
// return a-b;
// })
//上述函数可以写成下面这个形式
arr.sort((a,b)=> a-b);//就只留下参量,用箭头指向函数块
console.log(arr); //得到正常排序结果
箭头函数会固定this指向,固定的this是当前的环境,就是你定义this的时候,所处环境中this的指向,注意这里定义时,就是一开始这个this就是指向window的,通过箭头函数固定了下来,后面不管什么对象调用,这个this指向都不变。参考以下代码
let json = {
a : 12,
fn : function(){
console.log(this);
console.log(this.a);
}
}
let date = new Date();
date.fn = json.fn; //函数this指向到了date上,date并没有this.a
//谁调用的,this指向谁
date.fn(); //结果 时间,undefined
// 字面量定义对象
let json2 = {
a : "字面量定义的",
fn : () => { //箭头函数会固定this指向,固定的this是当前的环境
//就是你定义this的时候,所处环境中this的指向,注意这里定义时,就是一开始这个this就是指向window的
//通过箭头函数固定了下来,后面不管什么对象调用,这个this指向都不变
console.log(this);
console.log(this.a); //window上没有a
}
}
json2.fn(); //结果 window undefined
//使用class来定义对象
class Json { //这里的this的指向,是指向Json的。使用构造函数也是同理
constructor(){
this.a = "类定义";
this.fn = () => {
console.log(this.a);
}
}
}
let json3 = new Json();
json3.fn(); //结果 类定义
//使用构造函数
function Json4() {
this.a = "构造函数";
this.fn = () => {
console.log(this.a);
}
}
let json4 = new Json4();
json4.fn(); //结果 构造函数
1.收集剩余参数
在参数中使用,要求剩余参数只能在最后,后面不可以再放了
function show(a,b,...c){ //收集剩余参数到c,要求剩余参数只能在最后,后面不可以再放了
console.log(a,b,c);
}
show(1,2,3,4,5,6); //返回结果 1 2 Array[4]-->[3,4,5,6]
2.数组的展开
数组中有什么内容,展开后返回的就是什么内容arr[1,2,3] ----> …arr == 1,2,3
let arr = [1,2,3];
function add(a,b,c){
console.log(a + b + c); //打印结果6
}
add(...arr); //通过展开来写,...arr 相当于 1,2,3
//所以有了数组链接的新方法
let arr2 = [4,5,6];
let arr3 = [...arr,...arr2];
console.log(arr3);
3.对象的展开
//对象展开也是一样
let person = {
name : "张三",
age : 18,
say : () => {
console.log("Hello!");
}
}
let student = {
...person,
class : "一班",
score : 100
}
console.log(student);
映射: 一一对应
[60 , 50 , 90] => [及格,不及格,及格]
let arr = [67, 78, 58, 89, 90];
let arr2 = arr.map(function (item){
if(item >= 60){
return '及格';
}
else{
return '不及格'
}
}) //映射完成后,才返回结果,所以有多少个返回多少个结果
//简化后的写法
arr2 = arr.map(item => item>=60?'及格':'不及格');
console.log(arr,arr2);
缩减: 多对一
n => 1 比如求和、求平局数
let score = [67, 78, 58, 89, 90];
let avg = score.reduce(function (tmp, item, index){
console.log(index+':'+tmp+ ', '+ item); //tmp一开始会把第一个值取出来,后面就是undefined,除非有返回值
//注意index的值是对应item的,item是从score[1]开始的
if(index == score.length - 1){
return (tmp + item)/ (score.length)
}else{
return tmp + item;
}
});
//优点,可以同时将前面遍历产生的结果和当前遍历项进行计算
console.log(avg);
//过滤,取出全部偶数
let arr = [66,59,78,45,23];
let arr2 = arr.filter(item => item%2==0) //返回true是,把item添加到arr2中,false则不操作
console.log(arr);
console.log(arr2); //取出所有偶数
let arr = [66,59,78,45,23];
arr.forEach((item,index) => {
console.log(`第${index}个元素是${item}`); //字符串模板,使用反引号,可以折行
})
1.用反引号表示字符串模板
2.字符串模板中,可以时用${}来获取变量,方便输出
3.字符串模板的所有的空格、缩进和换行都会被保留在输出中
let a = "方便"
var str = `字符串模板注意使用反引号
换行是实际存在的,并非形式上的
引用变量也很${a}`
console.log(str);