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()//李四在学习









