ES6
模板字符串
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干了什么?
- 创建一个空对象 ,
var obj = {}
- 设置obj原型的指向,
obj.__proto__ = Base.prototype
- 将Base中的属性和方法设置到obj中,
Base.call(obj)
注意这里会执行一次Base函数 - 返回新对象obj