JavaScript(ES6)

作用域

let
块级作用域,暂时性死区(不进行变量提升,在作用域头部到声明以前,不允许使用),特例:for循环的小括号和花括号都是一个新的作用域

const
原始类型值不允许修改 引用类型地址不允许修改

立即执行函数简写,一对花括号

解构赋值

数组

let [a,[[b],c]] = [1,[[0],2]];
console.log(a,b,c);

let [,,third] = [1,2,3];
console.log(third);

let [head,...tail] = [1,2,3,4,5];
console.log(head,tail);

//默认值,变量值是 === undefined的话才会使用默认值,默认值可以是变量函数等
let [a,b,c = 6] = [1,2,undefined];
console.log(a,b,c);

对象

// 对象匹配,按照key匹配,key可以相同,多次匹配
let {a,b} = {a:1, b:2};
console.log(a,b);

//默认值
let {a = 3} = {};
console.log(a) // a = 3

字符串

//字符串结构赋值
let [a,b,c] = '123';
console.log(a,b,c);

包装类

//包装类解构赋值
let {toString : s} = 123;
console.log(s === Number.prototype.toString);

函数

//函数参数的解构赋值
function f([a,b]){
    return a+b;
}
console.log(f(['hello', ' world']));

function f2({a = 0,b = 0} = {}){
    console.log(a,b);
}
f2({a:1,b:2});
f2({a:1});
f2(); //传入undefined,如果解构赋值 = {} 就是在不传参时有效,否则报错

从模块或者API中获取数据

//从模块或者API中获取数据
const {PI,cos,sin} = Math;
console.log(PI,cos,sin);

特例

// 特例
let [a] = [1];

let b;
({b} = {b:1});

//数组当对象,数组下标当key
let {0:a,1:b} = [1,2];
console.log(a,b);

拓展

字符串拓展

新增API

string.includes() //是否包含某个子串
string.startWith() / string.endWith() //是否以xx开头结尾
string.repeat(次数) //字符串重复多少次
string.padStart(num,str) / string.padEnd(num,str) //把字符串以str补充至要求的位数

模板字符串

数值拓展

进制表示法
二进制 :0bxxx  八进制 :0oxxx  十六进制 :0xaaa

最小常量
Number.EPSILON (如果两个数之间的差值小于该最小常量,则可以认为两个数相等
可以用作判断 0.1 + 0.2 === 0.3 等问题)

安全整数
判断安全整数 Number.isSafeInteger()
最大安全整数 Number.MAX_SAFE_INTEGER
最小安全整数 Number.MIN_SAFE_INTEGER

内置对象Math拓展

Math.trunc()  //去掉小数部分 
Math.cbrt()   //开立方根 
Math.hypot()  //对所有数据求平方和再开方 
Math.expml( x ) // 对数  返回的是 e^x - 1
Math.log1p( x ) //对数  返回的是 log(1 + x)
Math.log10(x)  //以10为底的对数    
Math.log2(x)  //以2为底的对数   
sinh()、cosh()、tanh()、asinh()、acosh()、atanh()  //双曲函数
指数运算 Math.pow(x,y)  简写 =>  Math.pow(x ** y)

函数拓展

箭头函数
函数体只有一行语句,不用加花括号,且return可省略,如有多行语句,照旧
箭头函数不初始化this,this是在箭头函数定义时确定,不是在调用时确定
箭头函数不能使用arguments对象,可以用rest(…args)参数代替
利用不断返回对象嵌套实现管道机制

函数形参
函数参数默认值注意的两个点:
1、如果传值,但是这个等价于false,此参数一定会被覆盖
2、不利于未来代码优化

//理由:空字符串等价于0(false),所以会把y变成2
function create(x,y){
    x = x || 1;
    y = y || 2;
    console.log(x,y);
}
create('hello','');  // hello 2

//理由:传入的参数不是undefined,所以默认值无效
function create2(x = 1,y = 2){
    console.log(x,y);
}
create2('hello','');  // hello _ 

不能声明和形参同名的变量
当形参有了默认值以后,形参不能重复声明
函数形参小心暂时性死区 -> 自己等于自己,自己等于块作用域里声明的变量,忽视声明顺序颠倒等于 也是不行的
函数形参按顺序读入,如果想要跳过某个参数给后面参数传参,只能填null、undefined

函数形参默认值的计算时惰性的

 let x = 9;
function f4(y = x + 1){
  console.log(y);
}
x = 10;
f4(); // 11

函数的属性
函数的length:函数需要的必须参数的个数

//如果遇到有默认值的参数,则后面的所有忽略不计
console.log((function(a,b,c){}).length);  // 3
console.log((function(a,b,c = 0){}).length);  // 2
console.log((function(a,b,c = 0,d){}).length);  // 2

函数的name

function f5(){};
let f6 = function(){};
let f7 = (function(){}).bind({});

console.log(f5.name); // f5
console.log(f6.name); // f6
console.log(f7.name); // bound _

this绑定
call(this,item,item)
apply(this,[item,item])
bind(this)(item,item)

数组拓展

拓展运算符(…)可展开可收拢

数组可以对字符串解构赋值,所以字符串也可以使用拓展运算符拓展成数组

 let array = [...'hello'];
console.log(array);  // ['h','e','l','l','o']

Array.from(target,自动调用map回调,绑定this) 把类数组转换成真正的数组,可以接收类数组,有length的对象,set,map

let obj = {
   '0':1,
    '1':2,
    '2':3,
    length:3
}
let array2 = Array.prototype.slice.call(obj);
let array3 = Array.from(obj);

Array.of()把零散的数据变成数组

let a = 5;
let arr1 = [1,2,3];
let arr2 = new Array(1,2,3);
let arr3 = Array.of(1,2,3);
let arr4 = Array.of(a); // 【5】
console.log(arr3);

实例的find(回调)、findindex(回调),回调有三个参数,返回第一个满足条件的数据

实例的fill(data,start,end) 填充数据

//该函数有三个参数。
arr.fill(value, start, end)

//value:填充值。
//start:填充起始位置,可以省略。
//end:填充结束位置,可以省略,实际结束位置是end-1。

var arr = ['0','1','2','3','4'];
arr.fill(1) // => 所有数据都要初始化为1 [1,1,1,1,1] 
arr.fill('填进去',3) // 从索引3开始填充数据 [0, 1, 2, "填进去", "填进去"]
arr.fill('新值',2,4) // 从索引2开始到索引4之前 [0, 1, "新值", "新值", 4]

实例的keys()、values()、entries()循环遍历

let arr6 = [1,2,3,4];
let entries = arr6.entries();
console.log(entries.next());

"分别对应下标和值,可以一步步走下去"
分别对应下标和值,可以一步步走下去

实例的includes() 数组是否包含某个元素 : 比indexOf好的地方:语义化 、 可以处理NAN

对象拓展

属性名表达式
Object.js()判断相等不相等,== ===多少有点问题

Object.assign(target,source,source…)

只会拷贝本身,不会拷贝prototype上的属性
拷贝是浅拷贝,不是深拷贝
如果有同名属性,后面覆盖前面
target如果不是对象,是string、number、boolean,会先转化为包装类
如果target是undefined或者null,无法转换成包装类,报错
如果source是string,可以计算(把字符串拆开),否则没有影响

应用:
应用于构造函数
class point {
    constructor(x,y){
        // this.x = x;
        // this.y = y;
        Object.assign(this,{x,y});
    }
}
console.log(new point(1,2));

在原型上添加函数
Object.assign(point.prototype,{
   f(){
        console.log(111);
    }
})

不能用对像解构赋值的时候,用这个API

Object.keys(),.Object.values(),Object.entries() : 这类都是使用for of

对象拓展运算符(…) : 可以像数组一样展开收拢

数据结构

Symbol
ES6新增的数据类型,创建一种独一无二不可改变的数据类型,主要解决防止全局变量冲突问题

BigInt
ES6新增的数据类型,是一种数字类型的数据,可以存储任意精度格式的整数,使用Bigint可以安全存储和操作大整数,即时这个数超出了Number的安全整数范围

Set

属性和方法

add(value),返回set实例,所以可以连续链式调用
delete(value)删除返回true/false
has(value)是否包含某个值
clear()清除所有成员
size 一共有多少成员

遍历
keys() / values() / entries() / foreach
对于 set 数据结构 ,key和value都是value的值, keys和values的遍历方法拿出来的值都是一样的,是value , 所以可以简写成 for(let item of s){} 所以不论哪种循环,全都是value

属于数组的方法,转换成数组进行遍历 : map、filter、Array.from等

运用set来回切换array运用filter实现并集、交集、差集

Map

定义 : Map和object都是键值对,区别在于object的键会强行转换成字符串,而Map没有这个要求

Map初始化

let array2 = [
	['a',4],
    ['b',3]
]

1、嵌套的二维数组构造Map
console.log(new Map(array2));

2、嵌套数组的set构造Map
let s2 = new Set(array2);
console.log(new Map(s2));

Map转换成数组

let array2 = [
	['a',4],
	['b',3]
]
let map = new Map(array2);
console.log([...map.entries()]); // [Array,Array]
console.log([...map]);  // [Array,Array]
console.log(Array.from(map));

当Map的key是字符串的时候,实现Map和Object的转换

1、Map转换为对象
function mapToObj(map){
	let obj = {};
    for(let [key,value] of map){
        obj[key] = value;
    }
    return obj;
}

2、对象转换成Map
function objToMap(obj){
  let map = new Map();
   for(let key in obj){
      map.set(key,obj[key]);
   }
   return map;
}

Map的key碰撞
增加[key,value],如果key是引用类型,看地址,如果地址一样将覆盖,如果是NaN自动用object.is判断,一样的话覆盖

常用属性和方法

set(key,value) 增加
get(key) 获取
delete(key)
has(key)
clear()
size

遍历
keys() / values() / entries() / foreach
entries() 使用这个遍历同时获取key,value的话,entries可以省略,直接写Map名即可

转换成数组进行遍历,Array.from/filter/map常用

总结:
快速获取key或者value值,map和set都可以 : […x.keys()] 类似,获得一个只包含key或者value的数组

WeakSet、WeakMap
1、跟Map/Set使用基本一致
2、区别:WeakSet所有的值必须是引用类型,WeakMap所有的key必须是引用类型
3、不会影响JS垃圾收集,而且不可遍历

 <div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
 let divs = document.querySelectorAll('div');
let map = new Map();
let data = {a:1,b:2};
//把DOM元素存到map数据结构中方便存取
map.set(divs[0],data);
//在map中存在引用,内存无法被释放,所以DOM元素无法自杀释放内存
divs[0].remove();

//又想方便存取,又想该释放就释放,只能使用WeakMap/WeakSet,因为不影响JS垃圾收集
let weakmap = new WeakMap();
weakmap.set(divs[0],data);
divs[0].remove();

4、作用:防止内存泄漏

Promise

解决回调地狱的问题

  • 特点:
    • 进行时 pending
    • 已成功 fulfilled
    • 已失败 rejected
    • 最开始是pending状态
      • 一种转化:从pending状态转换为fulfilled状态
      • 另一种转化:pending状态转化为rejected状态
      • 和事件的区别:事件在出发后绑定函数,不会触发,promise状态发生改变后绑定函数仍然会触发,promise无法取消

1、promise初始化步骤:

  • 构造函数初始化,初始this.value this.reason resolve函数 reject函数
  • executor函数是promise的构造函数参数,有两个参数(resolve,reject)
  • executor是用户自定义的同步函数,是决定promise状态如何变化的函数,
  • executor以同步或者异步的方式调用resolve/reject
  • 如果调用resolve函数,promise由初始状态pedding -> fulfilled
  • 如果调用reject函数,promise由初始状态pedding -> rejected

2、then

  • then是异步的,作用是为promise对象状态改变所触发的回调函数 onFulfilled、onRejected
  • resolve()/reject() 可以向 onFulfilled onRejected 传递参数

3、在executor函数中根据resolve/reject传入的参数决定当前promis对象的状态,从而决定then的调用抉择

  • 情况1:如果调用resolve/reject传入的参数是原始类型或者非promise对象,promise的状态变为Fulfilled/Rejected
  • 情况2:如果调用resolve/reject传入的参数是promise对象,那么,当前的promise对象一直保持pedding状态,
    直到给入的参数promise对象状态发生改变,此时原promise的对象状态发生同样改变,并且拿到参数promise对象
    的数据(与参数promise对象的状态一致)

4、then回调的返回,影响then所返回Promise对象的状态

  • 对于任何一个then,都会返回一个新的promise对象,且与resolve/reject参数中的promise或者
    onFulfilled、onRejected返回的promise不是同一个对象,是一个全新的Promise对象
  • 情况1:onFulfilled/onRejected被调用,返回了非promise对象(有返回值,没返回值),
    then返回的promise对象:状态变为Fulfilled,返回值会传递给then返回的promise对象
  • 情况2:onFulfilled/onRejected被调用,返回了promise对象
    then返回的promise对象:与回调返回的promise对象状态一致,回调返回的promise对象的数据 会传递给then返回的promise对象
  • 情况3:then没有设定onFulfilled/onRejected,then返回的promise对象与调用then的promise对象状态一致,
    会传递调用then的promise对象数据给then返回的promise对象

5、then的链式调用,根据第4点的三种情况决定then返回promise对象的状态

6、catch(onRejected) 等价于 then(null,onRejected)
best practice: 通常then只设定成功回调,在最后catch()处理失败回调

7、reject的三种方法(跟then只写成功回调,在最后执行catch类似,常用方法二三)

//方法一:
let p = new Promise((resolve,reject)=>{
    reject('failed');
})
p.catch(err=>{
    console.log(err);   
})

//方法二:
let p = new Promise((resolve,reject)=>{
    try{
        throw new Error('failed');
    }catch(e){
        reject(e);
    }
})
p.catch(err=>{
    console.log(err);   
})

//方法三:
let p = new Promise((resolve,reject)=>{
    reject(new Error('failed'));
})
p.catch(err=>{
    console.log(err);   
})

8、Promise的API

promise.all([p1,p2,p3...])
返回值是新的promise对象
1.没有任何一个px是Rejected状态的,有PX是pending状态,则返回的promise状态是pending
2.所有px都是fulfilled状态 , 返回的promise对象是fulfilled
3.存在状态是Rejected的,返回的状态是Rejected

promise.rate([p1,p2,p3...])
返回值是第一个px的状态,并且获得它的数据

9、Promise.resolve()的使用

 //1、Promise.resolve(原始类型)
//返回值:返回一个新的Promise对象,状态fulfilled,原始类型作为data返回
 var p = Promise.resolve('failed');
 p.then((data) => console.log(data));


//2、Promise.resolve(Promise)
//   返回值:就是传入的Promise对象
var p = new Promise((resolve,reject) => {
    resolve('succeed');
});

var p2 = Promise.resolve(p);
console.log(p === p2);   // true

//3、 Promise(thenable对象)
//    thenable对象: 有一个then函数,其实是exector
//    返回值:使用then函数作为exector初始化新的promise对象
var thenable = {
    then(resolve,reject){
        resolve('succeeed');
    }
}
var p = Promise.resolve(thenable);
p.then(data => console.log(data));


//4、Promise(非thenable对象)
//   返回值:返回一个新的promise对象,状态fulfilled, 非thenable对象作为data返回
 var obj = {
     name:'占山',
     age: 15
 }
var p = Promise.resolve(obj);
p.then(data => console.log(data));

10、Promise.reject()

 //1、Promise.reject(原始类型)
//返回值:返回一个新的Promise对象,状态rejected,原始类型作为data返回
 var p = Promise.reject('failed');
 p.catch((data) => console.log(data));

11、promise串行

 //完成20个任务,成功下一个,失败继续尝试
//串行
function perAction(){
    return (new Promise((resolve, reject) => {
        setInterval(() => {
            Math.random() > 0.5 ? resolve() : reject();
        }, 1000);
    }))
}
function doAction(index,total){
    if(index < total){
        perAction().then(()=>{
            console.log(`${index + 1} task is succeed!`);
            index++;
            doAction(index,total);
        }).catch(()=>{
            console.log(`${index + 1} task is failed!`);
            doAction(index,total);
        })                
    }
}

doAction(0,20);

promise并行

//并行完成20个任务,成功下一个,失败继续尝试

//配置:每一个任务
function perAction(i){
    return (new Promise((resolve, reject) => {
        Math.random() > 0.5 ? resolve() : reject();
    }))
}

//开始并行
//配置:是否所有任务全部成功运行
function doActionSucceed(total){

        //配置:任务失败  递归
    function _taskReRun(i,callback){
        let p = perAction(i);
        p.then(()=> {
            callback(i);
            console.log(`${i} succeed`);
        }).catch(() => {
            _taskReRun(i,callback);
            console.log(`${i} failed`);
        });
    }

    return (new Promise((resolve,reject) => {
        let map = new Map();
        for(let i=0; i<total; i++){
            //第二个参数传个箭头函数作为callback传给taskReRun函数
            _taskReRun(i,i => {
                map.set(i,true);
                if(map.size == total){
                    resolve();
                }
            });
        }
    }))
}

doActionSucceed(20).then(data => console.log('all finish'));

12、async/await(串行)

  • async 修饰函数定义
    • 函数会天然返回promise对象,如果不是,会自动调用promise.resolve()
    • 一旦一个函数使用async,那么调用它的方式一定是异步的
    • 返回的promise对象:在async修饰的函数结束后一定是fulfilled,
      如果任意一个await rejected ,那么返回的promise对象状态变为rejected
  • await 在函数调用前
    • 被调用函数应当返回一个promise对象
    • 在函数内部,await会阻塞函数的执行,直到被调用函数返回的promise状态发生变化

async await 实现串行

//串行,如果成功,持续串行,如果失败,跳出

//配置:随机成功或者失败
function randomPromise(task){
    return (new Promise((resolve,reject) => {
        console.log(`------------task ${task} ----------------`);
        Math.random() > 0.5 ? resolve(`task ${task} succeed`) : reject(`task ${task} failed`);
    }))
}
//配置:串行,失败即跳出
async function returnPromiseWithAsync(total){
    for(let i=0; i<total; i++){
        await randomPromise(i);
    }
}

returnPromiseWithAsync(10).then(value => console.log(value)).catch(reason => console.log(reason));

async await 实现串行

//串行,如果成功,持续串行,如果失败,rerun

//配置:随机成功或者失败
function randomPromise(task){
    return (new Promise((resolve,reject) => {
        console.log(`------------task ${task} ----------------`);
        Math.random() > 0.5 ? resolve(`task ${task} succeed`) : reject(`task ${task} failed`);
    }))
}


//配置:如果一个任务失败,rerun    递归
function taskReRun(task){
    return randomPromise(task).catch(() => taskReRun(task));
}

//配置:开始串行
async function returnPromiseWithAsync(total){
    for(let i=0; i<total; i++){
        await taskReRun(i);
    }
}

returnPromiseWithAsync(10).then(value => console.log(value));

async await 实现并行

//并行,最后 all finish

//配置:随机成功或者失败
function randomPromise(task){
    return (new Promise((resolve,reject) => {
        console.log(`------------task ${task} ----------------`);
        Math.random() > 0.5 ? resolve(`task ${task} succeed`) : reject(`task ${task} failed`);
    }))
}


//配置:如果一个任务失败,rerun    递归
function taskReRun(task){
    return randomPromise(task).catch(() => taskReRun(task));
}

//配置:开始串行
async function returnPromiseWithAsync(total){
    let map = new Map();
    //每执行一次任务,加入到map集合种,无论是否状态改变
    for(let i=0; i<total; i++){
        let p = taskReRun(i);
        map.set(i,p);
    }
    //一个个检查,所有都完成了,函数退出
    for(let i=0; i<total; i++){
        await map.get(i);
    }
}

returnPromiseWithAsync(10).then(value => console.log('all finish'));

使用try catch 实现async await串行

//串行,如果成功,持续串行,如果失败,rerun

//配置:随机成功或者失败
function randomPromise(task){
    return (new Promise((resolve,reject) => {
        Math.random() > 0.5 ? resolve(`task ${task} succeed`) : reject(`task ${task} failed`);
    }))
}


//配置:如果一个任务失败,rerun    递归
function taskReRun(task){
    return randomPromise(task).then(() => {
        console.log(`task ${task} succeed`);
    }).catch(() => {
        console.log(`task ${task} failed`);
        taskReRun(task);
    });
}

//配置:开始串行
async function returnPromiseWithAsync(total){
    try{
        for(let i=0; i<total; i++){
            await taskReRun(i);
        }
        console.log('all finish');
    }catch(e){
        console.log('some failed');
    }
}
returnPromiseWithAsync(20);

使用 try catch 实现 async await并行

//并行,最后 all finish

//配置:随机成功或者失败
function randomPromise(task){
    return (new Promise((resolve,reject) => {
        console.log(`------------task ${task} ----------------`);
        Math.random() > 0.5 ? resolve(`task ${task} succeed`) : reject(`task ${task} failed`);
    }))
}


//配置:如果一个任务失败,rerun    递归
function taskReRun(task){
    return randomPromise(task).catch(() => taskReRun(task));
}

//配置:开始串行
async function returnPromiseWithAsync(total){
    try{
        let map = new Map();
        //每执行一次任务,加入到map集合种,无论是否状态改变
        for(let i=0; i<total; i++){
            let p = taskReRun(i);
            map.set(i,p);
        }
        //一个个检查,所有都完成了,函数退出
        for(let i=0; i<total; i++){
            await map.get(i);
        }
        console.log('all finish');
    }catch(e){
        console.log('some failed');
    }
    
}

returnPromiseWithAsync(10)

Class

  • 用ES5写法构造对象,不用new顶多挂到window上,可以运行。用class的写法,构造对象时必须要使用new,否则报错
  • function存在变量提升,class不存在变量提升

使用Class定义构造函数的两种写法

class Person {
	//写成这个样子的函数/变量是写在prototype上的
    constructor(name,age){
        Object.assign(this,{name,age});
    }
    say(){
        console.log('hello world');
    }
}
let obj = new Person('张三', 25);
console.log(obj);

//以立即执行函数的形式构造对象
 let obj = new class {
	constructor(name,age){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log('hello world');
        console.log(Person.name);  // Person
    }
}('张三', 25);

ES6的Class 与 ES5构造函数 的异同

//相同点
console.log(Person === Person.prototype.constructor);  //true
console.log(p.constructor === Person.prototype.constructor);  //true
console.log(p.say === Person.prototype.say);    //true

//不同点
//用class方法定义的原型函数,不可枚举,有ES5定义的原型函数可以枚举
console.log(Object.keys(Person.prototype)); // []

访问实例原型的异同

//ES5写法
console.log(obj.__proto__);
//ES6写法
console.log(Object.getPrototypeOf(obj));

Class表达式

  • Person名分两种情况
    • 情况一:Person作为class内部的名字,只在内部有效,外部无法调用
    • 情况二:Person名字可省略
const myClass = class person{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    say(){
        console.log('hello world');
        console.log(Person.name);  // Person
        console.log(myClass.name);  // Person
    }
}

Class中的this问题

class Person{
    constructor(name,age){
        this.name = name;
        this.age = age;
        //方法一:
        this.say = this.say.bind(this);
    }
    //方法二:改用箭头函数,箭头函数调用不初始化this,使用定义地方的this
    say(){
        console.log(this.name);
    }
}

function f(callback){
    callback();
}

let obj = new Person('张三', 25);
f(obj.say);  //函数调用会初始化this,如果解决obj.say的this问题

Class的get / set

class Person{
    constructor(name,age){
        this.name = name;
        this.age = age;
    };

    set name(data){
        name = data;
    }
    get name(){
        return name;
    }
}

Class的静态方法和属性(通过类名、构造函数名访问静态方法/属性)

class Person{
    //静态属性或者方法
    static num = 5;
    static f(){
        console.log('f');
    }
    constructor(name,age){
        this.name = name;
        this.age = age;
    }

    set name(value){
        name =value;
    }
    get name(){
        return name;
    }
}
//外部静态属性/方法
Person.num = 5;

Class继承

  • super介绍
    • super() 代表基类构造函数
    • super()必须在构造函数中调用。 ES5:先有this,后调用基类构造函数。 ES6:this是super是初始化的
    • 在派生类构造函数完成以前,必须调用基类构造函数
    • 在调用super()以前,不能使用this
  • super作用
    • super() 当作调用基类构造函数使用
    • super 充当对象使用(在普通函数中)
      • 如果super后面的是属性,在读取值时,充当基类原型对象
      • 如果super后面的是属性, 在赋值的时候,充当派生类this作用
      • 如果super后面的是方法, 调用的是基类原型的方法,绑定的this是派生类的this
    • 不能确定super是以对象还是调用构造函数的方法使用时,报错
class Person{
    constructor(){
        this.name = '张三';
        this.age = 15;
        this.say = this.say.bind(this);   //给say函数绑定this,以至于后期把obj.say作为参数传递丢失this
    }
    say(){
        console.log('hello world');
    }
}
class Student extends Person{
    constructor(id,sex){
        //1、super()当作调用基类构造函数使用
        super();   
        //2、super() 代表基类构造函数
        //  2-1、super()必须在构造函数中调用。 ES5:先有this,后调用基类构造函数。 ES6:this是super是初始化的
        //  2-2、在派生类构造函数完成以前,必须调用基类构造函数
        //  2-3、在调用super()以前,不能使用this
        this.id = id;
        this.sex = sex;
    }
}
var obj = new Student(001,'male');
console.log(obj.say);
console.log(obj.name);
console.log(obj.sex);

模块

ES6:import / export(静态)
export / impor: 必须写在顶级和静态的,不能写在某个执行体内部

脚本拿到import的时候先静态处理,从目标文件中抓取相应的东西,把所有东西提升到顶部,然后才开始运行,所以就算import写在脚本最后,前面的执行体也可以拿到数据,一般建议写开头

//文件名:document.js :
var a = 5;
function f(){
    console.log('hello');
}

//必须写在脚本全局位置
//1、
export {a,f};
//2、
export {a as a1, f as f1};   //以别名方式返出给外界

//3、
var a = 5;
//使用default,接收那边可以使用任何名称, export default只能用一次
//如果target是变量的话,不允许在 export default 上直接定义, 例如:export default var a = 5 这样写
export default a;  // 等价于 export {a as default}
// 或者
export default function f(){console.log('hello')};   // 此时target是函数表达式

export {a,f};



//文件名:index.js

//必须写在脚本全局位置
//1、
import {a,f} from './document.js'
//2、
import {a1,f1} from './document'  //如果后缀是js / mjs , 可以省略

// 把document.js传出来的所有东西挂载在A对象上, A对象不可拓展不可删除不可修改
// A底下的如果是个对象,那么这个对象类内部的(key,value)就可以更改
import * as A from './document'  


//3、
import aaa,{a,f} from './document';
import ffff,{a,f} from './document'; 

CommonJS:module.export / require

  • 动态的,运行时加载,被加载的是一个对象
  • node.js广泛使用这种方法
//文件一:
var a = 5;
function f(){
	console.log('hello');
}

module.exports = {
	a : a,
	f : f
}

//文件二:
var A = require('./文件一');
  • CommonJS其实对脚本内对象的拷贝,如果是原始类型,传出去后不会再改变数值,如果是引用类型那么会改变。 在文件二中调用f方法,A.a的值不会改变,如果A.a想要同步发生改变,就以 get的方式把a传递出去
//文件一:
var a = 5;
function f(){
    a++;
}

module.exports = {
    get a(){
        return a;
    },
    f
}


//文件二:
var A = require('./a.js');
console.log(A.a);  //5
A.f();
console.log(A.a);  //6

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值