1,let、var
1.1 var
ES5中创建变量使用var,var关键字定义的变量有两个作用域,全局作用域和局部作用域
-
全局变量:在全局范围内定义的变量
-
局部变量:在函数内部定义的变量 比如循环,判断语法块
1.2let
ES6中创建变量用let,let关键字定义的变量有三个作用域,全局作用域、局部作用域、块级作用域
-
块级作用域:在语法块中定义的变量
1.3let和var两点主要区别的总结:
-
var在统一作用域可以重复定义同一个变量,let不行
-
var 没有块级作用域,在循环中定义的变量都是全局的,会相互覆盖,let在循环中定义的变量都是独立的,互不影响
举例1:let在同一作用域不能重复定义同一个变量,var可以
let在语法块中定义的变量,只能在语法块中使用
if (true) { var d = 4; let e = 5; } console.log(d); //4 console.log(e); //undefined
举例2:let在循环中定义的变量都是独立的,不会相互覆盖,var没有块级作用域,在循环中定义的变量都是全局的,会被相互覆盖
for (var i = 0; i < 5; i++) { var count = i; console.log(count); //0,1,2,3,4 setTimeout(function() { console.log(count); //444444 }, 100); let number = i; setTimeout(() => { console.log(number); //0,1,2,3,4 }, 200); } console.log(i); //undefined 循环变量i建议使用let定义,在循环之外无法调用,也就避免了全局作用域污染
-
在循环中使用var定义变量,这个变量是全局变量,每次循环的count共享一个作用域,所以下次循环的count把上次循环的count替换掉,循环之后,全局只有一个count,值为4
-
在循环中使用let定义变量,这个变量是块级变量,每次循环都会在一个新的块级作用域中定义一个独立的块级变量number,循环结束后,就有5各块级变量number,他们的值给不相同,互不影响
举例3:var定义变量可以重复定义,但是let不能再同一个作用域里边重复定义变量
var count1 = 100; var count1 = 200; console.log(count1); let number1 = 100; let number1 = 200; console.log(number1);//编辑器直接爆红线
1.4在循环中添加计时器或事件绑定,需要保留每次循环的变量值的方案
有以下两种解决方案:
-
1.使用let定义块级变量
for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 300); }
-
2.使用闭包,保持count局部变量
function outter(count) { return function inner() { console.log(count); } } for (var i = 0; i < 5; i++) { setTimeout(outter(i), 300); }
2,const定义常量
使用const定义的是常量,它只能/必须初始化一次,所谓初始化就是用const定义的常量必须有初始值。初始化之后不可修改,不能重新赋值。
2.1const定义值类型数据,绝对不能改
const c = 3; c = 4; //TypeError: Assignment to constant variable.报错
2.2 const定义引用类型数据,数据内容(对象/数组 中的数据)可以修改,引用类型本身(内存地址)不能改
const student = { name: "zhangsan", age: 20 } student.name = "lisi" student.sex = "男"
3,模板字符串
字符串模板用于字符串拼接,由于模板字符串支持换行,所以可以用来渲染字符串
var year = 2020, month = 4, day = 20; var htmlStr = ` <ul> <li>${year}年</li> <li>${month}月</li> <li>${day}日</li> </ul> ` console.log(htmlStr); console.log((`${year}年${month}月${day}日`));
4,箭头函数
-
普通的函数不能转化为箭头函数,只有匿名函数可以转化为箭头函数
-
var add = function() {} var add = () => {}
4.2 箭头函数的this指向
在事件函数、计时器、异步回调函数中可以保留this上下文(全局作用域)指向
举例1:箭头函数的this指向
// 在node环境下,this默认指向空对象 console.log(1, this); //{} // 可以修改这个对象 this.name = "全局zhangsan" console.log(2, this); //{ name: '全局zhangsan' } // setTimeout会把this指向修改为 Timeout对象 setTimeout(function() { console.log(3, this); //Timeout对象 }, 1000) // 箭头函数会保留this的上下文指向,使this指向和setTimeout外部的this值相同 setTimeout(() => { console.log(4, this); //{ name: '全局zhangsan' } }, 1000);
4.3 箭头函数的简化
-
如果箭头函数只有一个参数,可以省略小括号
-
如果箭头函数的函数体只有一句return返回,return和{}可同时省略
-
在对象中箭头函数可以直接省略箭头和冒号
var add = count => { return ++count }; var add = count => ++count; // 箭头函数在对象中的写法,对象中的函数有以下三种写法 var student = { name: "张三", age: 20, // ES5函数的写法,其中的this使当前对象 eat: function() { console.log(this.name + "吃饭"); }, // ES6箭头函数写法,其中的this是对象上下文(全局作用域)指向 drink: () => { console.log(this.name + "喝水"); }, // 简化写法,其中this的指向还是当前对象 sleep() { console.log(this.name + "睡觉"); } }; student.eat() student.drink() student.sleep()
5,数组、对象的解构
5.1数组的解构
一般,使用数组中的数据要使用索引取值。
5.1.1数组解构使用变量读取数组中的数据
注意:由于数据有顺序,在解构时,一般前边变量个数和数组中的数据个数要一一对应
var array = [1, 2, 3, 4]; let [count1, count2, count3, count4] = array console.log(count3);//3
5.1.2 使用 ...语法解构数组中的一部分数据
let [num1, ...num2] = array; console.log(num2);//[2,3,4]
5.2数组的赋值
使用 ...数组赋值
var array = [1, 2, 3, 4]; var array2 = ["a", "b", "c"]; console.log(...array2);//a b c array.push(...array2); console.log(array);//[1,2,3,4,'a','b','c']
5.3 对象的解构
如果要获取一个对象中的某个字段,直接用对象打点调用即可,也可以使用对象解构写法获取某个字段值
var student = { name: "张三", age: 12, sex: "男", phone: "110" }; console.log(student.phone);//110 var { age, sex } = student; console.log(age, sex); //12 男
注意:由于对象中的数据没有顺序,所以对象解构无需把所有字段都写上,可以按需求定义变量读取对象中的某一个或几个字段即可,但必须保证变量名和字段名相同
5.4 对象的赋值
var obj1 = { age: 20 } var obj2 = { sex: true } console.log({...obj1, ...obj2 });//{ age: 20, sex: true }
6,函数参数的默认值
6.1ES5
-
ES5中js函数定义时有两个参数,调用时就必须传入至少两个参数
-
如果传入的实参少于形参的个数,为防止错误,可以给形参设置默认值
-
设置默认值使用 || 设置
function add2(a, b) { a = a || 0; b = b || 0; console.log(a + b); } add2() //0 add2(3) //3 add2(3, 4) //7 add2(3, 4, 5) //7
-
如果参数个数不确定,通过arguments字段获取所有参数数组
function add4() { // arguments是一个类数组,里边放了所有参数 console.log(arguments, Array.from(arguments)); } add4() //{} [] add4(3) //{ '0': 3} [ 3] add4(3, 4) //{ '0': 3, '1': 4} [ 3, 4] add4(3, 4, 5) //{ '0': 3, '1': 4, '2': 5 } [ 3, 4, 5 ]
6.2 ES6
ES6通过形参 ...array获取参数数组,形参array是所有参数所在的数组
function add5(...array) { // 形参array是所有参数所在的数组 console.log(array); } add5() // [] add5(3) // [ 3] add5(3, 4) // [ 3, 4] add5(3, 4, 5) // [ 3, 4, 5 ]
7,对象的自变量创建
js中有两种创建对象的方法:1,使用new关键字创建对象 2,使用字面量创建对象 3,在ES6中字面量创建对象,如果属性名和属性值一样就可省略不写属性名
let date = new Date(); let obj = { name: "张三" };
let name = "zhangsan"; let age = 20 let obj1 = { name: "张三", age: 20, sex: "男" }; // 此时字段name和age已经提前好了变量,所以在对象中可直接引用变量值 let obj2 = { name: name, age: age, sex: "男" }; // 此时发现,对象中字段名 和 值得变量名一样,ES6中规定可简化 name:name ----> name let obj3 = { name, age, sex: "男" }; console.log(obj3);//{ name: 'zhangsan', age: 20, sex: '男' }
8,类的创建与继承
8.1 类的创建
类需要用到class关键字创建,格式为 class 类名 {},类中含有构造函数和属性,在类中创建属性用到this。
function People(name) { // this是构造函数创建的对象,name是对象的属性 this.name = name } var zhangsan = new People("张三") console.log(zhangsan);//People { name: '张三' }
class Student { // constructor是类的构造器,相当于构造函数 constructor(name) { this.name = name; this.study = function() { console.log(this.name + "在学习"); } } } var xiaoming = new Student("小明"); console.log(xiaoming); xiaoming.study(); //小明在学习
8.2 类的继承
继承::把一个类(父类)的属性和方法传递给另一个类(子类),可以让另一个类(子类)的对象调用
class Pupil extends Student { constructor(name) { // super指父类的构造器,通过父类的构造器创建子类对象 super(name) } } var a = new Pupil("李四") console.log(a);//Pupil { name: '李四', study: [Function (anonymous)] } a.study()//李四在学习