箭头函数
箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。
没有单独的this
在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值:
- 如果是该函数是一个构造函数,this指针指向一个新的对象
- 在严格模式下的函数调用下,this指向undefined
- 如果是该函数是一个对象的方法,则它的this指针指向这个对象
- 等等
This被证明是令人厌烦的面向对象风格的编程。
箭头函数表达式对非方法函数是最合适的。
prototype _proto_ constructor 原型链和原型对象
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法。
使用对象的构造器(constructor):
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
var myFather = new Person("John", "Doe", 50, "blue");
var myMother = new Person("Sally", "Rally", 48, "green");
在一个已存在的对象构造器中是不能添加新的属性的:
Person.nationality = "English";//不可行
要添加一个新的属性需要在在构造器函数中添加:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
this.nationality = "English";
}
原型链
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
__proto__ 属性,它是对象所独有的,可以看到__proto__属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象)。直到原型链顶端null。
通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链。
添加属性和方法
有的时候我们想要在所有已经存在的对象添加新的属性或方法。
另外,有时候我们想要在对象的构造函数中添加属性或方法。
使用 prototype 属性就可以给对象的构造函数添加新的属性:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
当然我们也可以使用 prototype 属性就可以给对象的构造函数添加新的方法:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
constructor
constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数
注意:
利用prototype重写构造函数后,constructor会指向你重新写的这个构造函数对象。
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype = {
getName: function() {
return this.firstName + " " + this.lastName;
};
}
就像是这个实例,重写后会指向:
function() {
return this.firstName + " " + this.lastName;
};
这个构造函数对象。
所以在重写prototype之后,要将constructor重新写回原构造对象
Person.prototype = {
constructor :Person;
getName: function() {
return this.firstName + " " + this.lastName;
};
}
this关键字
面向对象语言中 this 表示当前对象的一个引用。
但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
- 在方法中,this 表示该方法所属的对象。
- 如果单独使用,this 表示全局对象。
- 在函数中,this 表示全局对象。
- 在函数中,在严格模式下,this 是未定义的 (undefined)。
- 在事件中,this 表示接收事件的元素。
promise
- promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
- 并未剥夺函数return的能力,因此无需层层传递callback,进行回调获取数据
- 代码风格,容易理解,便于维护
- 多个异步等待合并便于解决
promise详解
new Promise(
function (resolve, reject) {
// 一段耗时的异步操作
resolve('成功') // 数据处理完成
// reject('失败') // 数据处理出错
}
).then(
(res) => {console.log(res)}, // 成功
(err) => {console.log(err)} // 失败
)
- resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去; reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
- promise有三个状态: 1、pending[待定]初始状态 2、fulfilled[实现]操作成功 3、rejected[被否决]操作失败 当promise状态发生改变,就会触发then()里的响应函数处理后续步骤; promise状态一经改变,不会再变。
- Promise对象的状态改变,只有两种可能: 从pending变为fulfilled 从pending变为rejected。 这两种情况只要发生,状态就凝固了,不会再变了。
最简单示例:
new Promise(resolve => {
setTimeout(() => {
resolve('hello')
}, 2000)
}).then(res => {
console.log(res)
})
分两次,顺序执行
new Promise(resolve => {
setTimeout(() => {
resolve('hello')
}, 2000)
}).then(val => {
console.log(val) // 参数val = 'hello'
return new Promise(resolve => {
setTimeout(() => {
resolve('world')
}, 2000)
})
}).then(val => {
console.log(val) // 参数val = 'world'
})
promise完成后then()
let pro = new Promise(resolve => {
setTimeout(() => {
resolve('hello world')
}, 2000)
})
setTimeout(() => {
pro.then(value => {
console.log(value) // hello world
})
}, 2000)
结论:promise作为队列最为重要的特性,我们在任何一个地方生成了一个promise队列之后,我们可以把他作为一个变量传递到其他地方。
async和await是如何处理异步任务的?
简单说,async是通过Promise包装异步任务。
比如有如下代码:
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
改为ES5的写法:
new Promise((resolve, reject) => {
// console.log('async2 end')
async2()
...
}).then(() => {
// 执行async1()函数await之后的语句
console.log('async1 end')
})