模板字符串
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