模板字符串

let name='kobe'
let age=19;
console.log(${name}'s age = ${age});   //kobe's age = 19

属性、方法的简写

name = 'kobe';
let user = {
    // name:name,  //老写法
    name,          //新写法
    // 新写法
    fun(){
        console.log('fun');
    },
    // 老写法
    fun1:function(){
        console.log('fun1');
    }
}
console.log(user.name);
user.fun();
user.fun1();

promise

// 以前的回调函数的写法
getData = (cb) => {
    setTimeout(() => {
        let data = 100;
        cb(data);
    }, 1000)
}
console.log(getData((data) => {
    console.log(data is ${data})
}));   // data is 100
// promise处理异步的写法
// resolve 处理成功  reject 处理失败
let p = new Promise((resolve, reject) => {
    setTimeout(()=>{
        let data = 100;
        resolve(data);
    }, 2000)
});
p.then((data)=>{
    console.log(promise data is ${data});
});

async await

async 让方法变成异步

await 等待异步方法执行完成

第一种,这种还是类似于回调的形式:

async function fun(){
    return 'i am fun';
}
console.log(fun());  // Promise { 'i am fun' }
//获取async方法里的数据
let as = fun();
as.then((data)=>{
    console.log(data)
});

第二种:用await,这种是ES7的写法

// 错误写法
let res = await fun();
console.log(res);

会报错:SyntaxError: await is only valid in async function

await只能用在异步方法里,因为他是等待一个方法结束,所以如果不用在异步方法里他就会把代码变成同步的,而阻塞程序。

async function awaitGetData(){
    let res = await fun();
    console.log('i am awaitGetData')
    console.log(res);
}
awaitGetData();

返回Promise的方法也可以用await,并不一定要是async方法。因为async方法也是返回的Promise。

let retProFun = ()=>{
    return new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve(888);
        }, 1000);
    });
};
async function te(){
    let data = await retProFun();
    console.log(data);
}
te();

js的继承

  • 原生JS的继承

  • 对象冒充实现继承(用call实现)

function Person(name){
    this.name = name;
    this.run = function(){
        console.log('i am ', this.name);
    }
}

Person.prototype.work = function(){
    console.log('here is work');
}

let p = new Person('Tim');
p.work()   
function Kobe(name){
    Person.call(this,name);
}
let kobe = new Kobe('Kobe Bryant');
kobe.run();
kobe.work();   // error 这种方式没法继承原型链上的属性和方法。
  • 原型链继承

前面代码不变,后面的改成这样:

function Kobe(name){
    // Person.call(this,name);
    Kobe.prototype = new Person();
    let kobe = new Kobe('Kobe Bryant');
	kobe.run();    // i am  undefined 
    kobe.work();   //  here is work
}

这种方式可以继承构造函数里面以及原型链上的属性和方法,缺点是没法给父类传参数

  • ES6写法
class Person{
    constructor(name){
        this.name = name;
    }
    setName(name){
        this.name = name;
    }
    getName(){
        return this.name
    }
}
let pp = new Person('kobe');
console.log(pp.getName())
class Player extends Person{
    print(){
        console.log('print', this.getName())
    }
    //静态方法
    static sayHello(){
        console.log('i am static')
    }
}
Player.age = 19   // 静态属性
let p1 = new Player('Tim')
p1.print()
Player.sayHello()

单例模式

创建多个实例,但是类的构造函数只执行一次。

class Person {
    static getInstance(){
        if (!Person.instence){
            Person.instence = new Person();
        }
        return Person.instence
    }   
    constructor(){
        console.log('i am constructor');
    }
    sayHello(){
        console.log('hello world')
    }
}
let p1 = Person.getInstance();
let p2 = Person.getInstance();
let p3 = Person.getInstance();

… 三个点的用法【拓展运算符】

  • 剩余参数
let sum = (...nums) => nums.reduce((pre, cur) => pre + cur, 0)
sum(1, 2, 3, 4);  // 10
  • 扩展运算符

针对可遍历对象。

字符串:

let l = 'kobebryant';
let a = [...l];  // [ 'k', 'o', 'b', 'e', 'b', 'r', 'y', 'a', 'n', 't' ]

数组:

let a = ['aa', 'bb', 'cc'];
let b = ['dd', 'ee', 'gg'];
let c = [...a, 'hhhh', ...b]; // [ 'aa', 'bb', 'cc', 'hhhh', 'dd', 'ee', 'gg' ]

有点像是复制了数组,但是这种方式其实是返回一个新数组,所以复制后的更改不会对原有数组造成影响。

对象解构

const {name, age} = person; // 类似这样就叫对象结构

如果要重命名变量,就 const {name:n, age} = person;// 这样就能取出name字段,但是会重命名为变量n

如果要以防没有字段而设置默认值const {name='have no name', age} = person;

这样如果那么不存在,依然能保证name是一个字符串。值得一提的是,这里是需要明确字段为undefined才会设置默认值,0,false等是不行的。

对象字面量拓展

const name = 'kobe';
const age = 2;
// 老写法
const person = {
    name:name,
    age:age
}
// es6写法,就是属性名一样的时候就可以不用重复写了
const person = {
    name,
    age
}
// 对象的方法也提供了简写
// 老写法
say:function(){
    console.log('i am say')
},
// es6
hello(){
    console.log('hello')
}

apply call

这两个方法是函数对象的方法,需要通过函数对象来访问。比如: fun.call()

function fun(){
	console.log('i am fun')
}
fun.call()    // 相当于直接调用fun()

apply,call可以将一个对象指定为一个函数执行时的this。

Person = {
	name:'kobe',
	say:function(){
		console.log('i am ', this.name)
	}
}
Player = {
	name:'tim'
}
Person.say()   // i am kobe
Person.say.call(Player)   // i am tim

apply和call两者的区别在于this实参后的参数类型

Person = {
	name:'kobe',
	say:function(a, b){
		console.log('i am ', this.name, a, b)
	}
}
......
Person.say.call(Player, 'a', 'b')   // this后面的参数类型是一个个传,
Person.say.apply(Player, ['a', 'b'])  // 传一个数组

arguments

首先,这玩意不是数组,他被叫做类数组,可以通过索引访问,且具有length,可以用来获取实参的长度。callee表示当前函数对象

function fun(){
	console.log(typeof arguments)  // object
	console.log( arguments.length)  // 0
	console.log(arguments.callee === fun)  // true
}
fun() 

因此,即时没有定义形参也可以通过索引arguments来使用,比如这种arguments[0]

__proto__ 和 prototype

https://github.com/vueSpa/vue-2.x-SoundCode/blob/master/prototype-proto.md

__proto__ 是字面对象的里的,如 a = {} 。prototype是构造函数里的,如var a = function(){}

new干了什么?

  1. 创建一个空对象 , var obj = {}
  2. 设置obj原型的指向, obj.__proto__ = Base.prototype
  3. 将Base中的属性和方法设置到obj中,Base.call(obj) 注意这里会执行一次Base函数
  4. 返回新对象obj