一、常用es6
const,let,箭头函数,解构赋值,模版字符串,扩展运算符…,class,promise,async:await,generator产生器,symbol数据类型,set,map等等。
1、const
a、定义常量,无法改变,但是对于引用类型的数据是可以改变的;定义时必须赋值初始化;
b、不允许重复声明,会报错;
c、有块级作用域的概念
d、无变量提升;
e、有暂时性死区问题
es5定义常量:
Object.defineProperty(window,'arg2'{value:1,writeable:false})
es5重新赋值不会生效,但也不报错,es6不会生效而且会报错
2、let
a、定义变量;
b、有块级作用域;
c、无变量提升;
d、有暂时性死区问题
es5的var定义的变量可以重新声明,会覆盖上一次的声明。
var无块级作用域,只有函数作用域和全局作用域。const,let有块级作用域:
if(true){
var a = 1;
}
console.log(a);//1----可以打印出1
if(true){
const b = 1;
}
console.log(b);报错,这里访问不到b
var有变量提升,let和const无变量提升
console.log(a);//可以打印为undefine
var a = 1;
console.log(b);//无法访问
const b = 1;
暂时性死区:
var a = 1;
if(true){
console.log(a);//这里就是暂时性死区,访问不到,会报错,虽然前面有a定义了,表明前后都可以访问,但是因为后面的const声明绑定了这个作用域,因为const无变量提升所以访问不到。
const a = 2;
}
注:let、const有块级作用域但是无变量提升,所以在它的作用域内在它还没声明前访问会报错
注:也有说let和const存在变量提升,只不过是声明提升,初始化和赋值没有,而var是声明和初始化提升了,function是声明,初始化和赋值都提升了,所以在其作用域内定义语句之前访问他们,let,const会报错称为暂时性死区,var不会报错,打印undefined,function可使用。
3、let和const谁更好,优先使用const。
问:引用类型如何冻结,即变成值改变不了的变量
const obj = {
a:1,
b:2,
c:[0,1,2]
}
Object.freeze(obj);
//以上可以冻结第一层,即第一层无法修改,但是第二层即子属性还是引用类型还是可以修改
//给出方案就是逐层冻结
function deepfreeze(obj){
Object.freeze(obj);
for(let key in obj){
if(typeof obj[key] == 'object'){
this.deepfreeze(obj[key])
}
}
}
二:箭头函数与普通函数的区别
普通函数:function a(){};const a = function(){}
箭头函数:const a = ()=>{}
1、this指向。普通函数this指向调用它的对象,箭头函数指向定义它的对象的上一层对象
2、在dom操作的回调里不使用箭头函数,因为箭头函数的this不指向调用它节点对象,很多数据就拿不到了
3、箭头函数无法构造类,即无法new出来一个实例。因为没有自己的this,也无法调用apply和call方法
4、箭头函数无法构造原型上的方法,没有prototype属性
5、箭头函数没有arguments对象。一定要用可以用rest参数代替
6、不可以使用yield命令,所以其不能作为generator函数。
箭头函数主要保留了上一级的this指向,书写更简洁。
三:class,类就是function的语法糖,助力js更加面向对象。
传统对象:
function Course(teacher,course){
this.teacher = teacher;
this.course = course
}
Course.prototype.getCourse = function(){
return `teacher${this.teacher},course${this.course}`
}
const course = new Course('li','数学')
es6:
class Course{
constructor(teacher,course){
this.teacher = teacher;
this.course = course}
}
getCourse(){
return `teacher${this.teacher},course${this.course}`}
}
}
const course = new Course('li','数学')
class就是function的语法糖,typeof Course就是function,class也有prototype
1、class有两种方法定义属性----构造器和顶层定义
class Course{
constructor(teacher,course){
this.teacher = teacher;//这就是构造器定义
this.course = course
// this._teacher = teacher;
}
set _teacher(val){this.teacher = val;}//顶层定义
get _teacher(){return this.teacher}
}
2、class构造只读变量使用set/get顶层定义属性,只写get不写set
class Course1 {
constructor(teacher, course) {
this._teacher = teacher;
this.course = course;
}
getCourse() {
return `teacher: ${this._teacher}, course: ${this.course}`;
}
get teacher() {
return this._teacher;
}
}
const course1 = new Course1('YY', 'ES6');
course1.teacher = '222';
// 修改只读变量会报错么? - 无法改变,但不会报错
3、构建私有变量----使用闭包或使用新方案的#name
class Course1 {
constructor(teacher, course) {
this._teacher = teacher;
let course = course;
// 在constructor作用域中定义局部变量,内部通过闭包的形式对外暴露该变量
this.getCourse = ()=>{return course}
}
getCourse2() {
return `teacher: ${this._teacher}, course: ${this.course}`;
}
//另一个方案
class Course3 {
#course = 'es6';
constructor(teacher, course) {
this._teacher = teacher;
}
}
get course() {
return `${#course}~`;
}
set course(val) {
if (val) {
this.#course = val;
}
}
}
4、静态方法
//es5
function Course(){}
Course.getCourse = function(){}
//es6
class Course{
constructor(){}
static getCourse(){}
}
//静态方法直接挂在,无需实力化直接获取
Course.getCourse();//可访问
5、继承
ES5 继承
function Course(teacher, course) {
this._teacher = teacher;
this.course = course;
}
Course.call = function() {//静态方法
console.log('calling');
}
Course.prototype.send = function() {
console.log('sending');
}
//子类继承
function child(teacher, course){
//初始化父类
Course.call(this,teacher, course);
this.start = function() {
console.log('starting');
}
}
// 实现继承
child.prototype = Course.prototype;//子类的原型链指向父类原型链,即可拿到父类原型链上的东西
es6继承
class Course {
constructor(teacher, course) {
this._teacher = teacher;
this.course = course;
}
send() {
console.log('sending');
}
static call() {
console.log('calling');
}
}
class Child extends Course{
constructor(){
super('老师',‘数学’);
}
newstart(){//子类的方法}
}
6、记录一下for in和for of 的用法
for (let key in obj){
console.log(key);
//如果obj是数组,则key为下标,是对象则为key
//且in. 可以遍历原型链上的属性和自定义属性
//遍历顺序不确定,enumerable为false时不会出现
}
for(let item of obj){
console.log(item);
//obj是数组,item为每一项的值,为对象则报错,说对象不是一个可跌代的东西,如果对象里加iterrator属性方法则可以迭代遍历
}
//但是对象可以这么处理去遍历
for(let [key,value] of Object.entries(obj)){
console.log(key,value);
//key 是对象属性,value是属性值,还有Obeject.keys(),Obeject.values()放方法取属性和取值返回一个数组
}
//对于数组可以直接用.keys(),.values(),.entries()方法
for(let key of arr.keys()){
console.log(key);//打印出的就是数组下标
//value打印的是值,entries打印的是【key, value】
}
//for of 也可以对字符串,但字符串不能直接用values()等方法,是和对象一样的用法,key 遍历出来是和数组一样的下表,字符在第几个位置的下标。
7、Iterator迭代器是用于遍历对象的一种接口,可以给不同的数据结构提供统一的循环方式实现遍历
具备原生的Iterator接口的数据结构Array、String、Set、Map、函数中的argument对象
Symbol.iterator:数据集合默认的遍历器生成函数,执行该函数便会返回一个遍历器对象
遍历器对象:
next():返回⼀个描述当前成员的信息对象,具有value和done两个属性,名称不可更改
原声迭代器使用:
{
const arr = [1, 2, 3, 4];
const fn = arr[Symbol.iterator]();
console.log(fn.next());
console.log(fn.next());
console.log(fn.next());
console.log(fn.next()); // {value: 4, done: false}
console.log(fn.next()); // {value: undefined, done: true}
}
自定义迭代器使用:
{
let obj = {
name: "dog",
weight: 123,
height: 12,
[Symbol.iterator]() {
// 索引
let index = 0;
let values = Object.values(obj);
return {
next() {
if (index < values.length) {
return {
value: values[index++],
done: false,
};
} else {
return { done: true };
}
},
};
},
};
for (const value of obj) {
console.log(value); // dog 123 12
}
}