Promise解析
是ES6规范中运用于new Promise()来生成实例,表示异步操作的最终结果的成功或失败。并且有三种状态pending(进行中)、resolved(已成功)、rejected(已失败)。
let promise = new Promise((resolved,rejected) => {
setTimeout(()=>{
let number = Math.ceil(Math.random()*100);//1-100随机数
if (number < 50) {
resolved('这是小于等于50的数')
} else {
rejected('数据超过50了')
}
},1000)
});
promise.then((value)=>{
//resolved的回调
},(err) => {
//rejected的回调
}).catch((err) => {
//rejected的回调
})
all的用法和race的用法
function A () {
let promiseA = new Promise((resolve,reject)=>{})
return promiseA
}
function B () {
let promiseB = new Promise((resolve,reject)=>{})
return promiseB
}
function C () {
let promiseC = new Promise((resolve,reject)=>{})
return promiseC
}
let promiseAll = Promise.all([A(),B(),C()])
promiseAll.then((value)=>{
//三个都成功则成功
},(value)=>{
//一个失败,则失败
})
let promiseRace = Promise.race([A(),B(),C()])
promiseRace.then((value)=>{
//谁快执行谁的回调
}).catch((err)=>{
//谁快执行谁的回调
})
手写简单封装Promise函数
function Promise(exe) {
let _this = this;//this指向保留
_this.status = 'pending';//promise的三种状态记录
_this.success = undefined;//保存成功回调传递值
_this.fail = undefined;//保存失败回调传递值
_this.onSuccessCallBack = [];//保存成功回调
_this.onFailCallBack = [];//保存失败回调
function resolve(success) {
if (_this.status == 'pending') {
_this.status = 'resolved'
_this.success = success;
_this.onSuccessCallBack.forEach(ele => {
element()
})
}
}
function reject(fail) {
if (_this.status == 'pending) {
_this.status = 'rejected';
_this.fail = fail
_this.onFailCallBack.forEach(ele => {
element()
})
}
}
try {
exe(resolve,reject)
} catch (err) {
reject(err)
}
}
Promise.prototype.then = function (onResolved,onRejected) {
let _this = this
if (_this.status == 'pending') {
_this.onSuccessCallBack.push(()=>{
onResolved(_this.success)
})
_this,onFailCallBack.push(() => {
onRejected(_this.fail)
})
}
if (_this.status == 'resolved') {
onResolved(_this.success);
}
if (_this.status == 'rejected') {
onRejected(_this.fail);
}
}
this解析
是ES5规范中关于this的指向,以及调用函数的call、apply、bind改变this的指向问题?this永远指向最后调用他的那个对象。this的最顶层的对象就是window(this === window)
1. 箭头函数:创建箭头函数时,箭头函数内的this指向外层的this。
let func = () => {
console.log(this) //Window
}
func()
2. new关键字:当使用new关键字时,函数的this指向新创建的对象。
function fn() {
consolo.log(this.a) //123
}
let obj = new fun();
obj.a = 123;
3. 直接调用:直接调用的函数,函数的this指向全局即为window。
function fn() {
//严格模式下是undefined
//非严格模式下是window
console.log(this);
}
fn();
4. 回调函数:函数的this总是指向window
setTimeout(function () {
//setTimeout的比较特殊
//严格模式和非严格模式下都是window
console.log(this);
});
改变this的指向
使用call、apply、bind函数可以改变this的指向,以及三者的区别。
call、bind、apply例子
let obj = {
name: "tony",
function() {
console.log(this)
console.log(this.name)
}
}
let thisArg = {name: 'Joy'}
obj.function.call(thisArg); //Joy
obj.function.apply(thisArg); //Joy
obj.function.bind(thisArg)(); //Joy
apply、call、bind的区别
fun.call(thisArg, param1, param2, ...)
fun.apply(thisArg, [param1,param2,...])
fun.bind(thisArg, param1, param2, ...)
thisArg(可选): fun的this指向thisArg对象。
param1,param2(可选): 传给fun的参数
相同:三者都是改变this的指向,且第一个传递的参数都是this指向的对象 不同:call和bind的传参是以序列的方式传递,而apply传参是以数组的形式传递, call和apply函数是直接执行的,而bind函数是返回一个函数,需调用在执行。
apply、call、bind运用场景
判断数据类型Object.prototype.toString.call() == '[object Object]'
获取数组的最大值最小值Math.max.apply(Math,array)、Math.min.apply(Math,array)
手写实现call
Function.prototype.mycall = function(context,...arr) {
if (context === null || context === undefined) {
//指定为null或undefined的this值会自动指向全局对象window
context = window
} else {
// 值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的实例对象
context = Object(context)
}
//用于临时存储函数
let special = Symbol()
// 函数的this指向隐式绑定到context上
context[special] = this;
// 通过隐式绑定执行函数并传递参数
let result = context[special](...array)
// 删除上下文对象的属性
delete context[special]
// 返回函数执行结果
return result
}
手写实现apply
Function.prototype.myapply = function(context) {
if (context === null || context === undefined) {
//指定为null或undefined的this值会自动指向全局对象window
context = window
} else {
// 值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的实例对象
context = Object(context)
}
//用于临时存储函数
let special = Symbol()
// 函数的this指向隐式绑定到context上
context[special] = this;
//获取本应传入原函数的参数
//ES6的扩展运算符可以使arguments这样的类数组转换成数组
let args = [...arguments].slice(1);
//从目的作用域中调用函数并获取返回值
let result = context[special](args);
// 删除上下文对象的属性
delete context[special]
// 返回函数执行结果
return result
}
手写实现bind
Function.prototype.mybind = function(context) {
//保存函数本身
let fun = this
// 可以支持柯里化传参,保存参数
let arg = [...arguments].slice(1)
// 返回一个函数
return function() {
//将原参数与返回函数的新参数拼接在一起
//支持柯里化形式传参
let newArg = arg.concat([...arguments])
//返回函数
return fun.myapply(context,newArg)
}
}
class解析
是ES6规范中的一个语法糖,其底层是通过构造函数去创建的。(语法糖:是避免编码出错提高效率的一种便携写法)
constructor()
是class类默认的方法,new生成对象实例时自动调用该方法,且clss不能变量提升。
//构造函数
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.introduce = function() {
return this.name
}
let info = new Person('张三',24)
console.log(info)
//class类
class Person {
constructor(name,age) {
this.name = name;
this.age = age;
}
introduce() {
return this.name
}
}
let info = new Person('张三',24)
console.log(info) //{name: '张三',age: 24}
静态方法、静态属性
- 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。
- 但如果在方法前加static关键字,就表示该方法不会被new实例继承,而是直接通过类来调用,这就是"静态方法",父类的静态方法可以被子类继承。
- 静态属性是指class本身的属性即Person.sex,而不是定义实例对象(this)上的属性。
class Person {
static sex = '男'
constructor() {
console.log(Person.sex) // 男
}
static classMethod() {
return 'hello'
}
static getMethods() {
this.callMethod()
}
static callMethod() {
console.log('call')
}
callMethod() {
console.log('nocall')
}
}
Person.classMethod() //console.log(Person.classMethod()) //hello
Person.callMethod() //call 如果静态方法包含this关键字,则this指向的是类而不是实例
let info = new Person()
info.classMethod(); //TypeError: info.classMethod is not a function
继承
- super关键字,既可以当作对象使用也可以当作函数使用,它表示父类的构造函数,用来新建父类的this对象。
- 子类有constructor()方法的必须有super()方法,且可以不写constructor()方法,否则报错。
- super在静态方法中指向父类静态方法,在普通方法中指向父类的原型对象.
class Father {}
class Son extends Father {
constructor(name,age,sex) {
//调用父类的constructor(name,age)
super(name,age)
this.sex = sex
}
introduce() {
//调用父类的introduce()
return this.sex + super.introduce();
}
}
let getSon = new Son()
//报错继承constructor方法中没有super方法
class Daughter extends Father {
constructor(){
}
}
let getDaughter = new Daughter() // ReferenceError
原型和原型链
原型:JS中每一个函数都有一个prototype属性,这个属性指向函数的原型对象,每一个由原型对象派生的子对象,都是相同的属性,子对象就叫构造函数,从实例原型中获取相同属性。 构造函数constructor:每个构造函数都有一个constructor属性,指向该关联的构造函数。 原型链:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,另一个原型中也包含这一个指向另一个构造函数的指针,层层递进,就构成了实例与原型的链条。