1.new关键字
function createNew(fn){
let obj = {} //1.新建一个对象
obj.__proto__ = fn.prototype //2.原型链接到构造函数的原型对象上
args = Array.prototype.slice.call(arguments,1) //获取后面参数
let result = fn.apply(obj,args) //3.改变this指向
return result instanceof Object ? result : obj //4.如果是对象就返回不是就返回原始值
}
function getName(name,age){
this.name = namethis.age = age
}
let a = createNew(getName,'pepsi','23')
console.log(a.name) //pepsi2.Promise
promise是有三个状态:pending,resolved,rejected,它接受一个自执行函数executor里面包含resolve和reject方法。resolve负责把状态从pending变为resolved并把值存起来,reject方法会把状态变为rejected,把失败的原因存起来,状态一旦发生改变就不会在变化。
class PromiseHand {
constructor(executor) {
let that = this
this.value = undefined
this.reason = undefined
this.status = 'pending'
//this.resolveList = []
//this.rejectList = []
let resolve = (val) => {
if (this.status === 'pending') {
this.value = val
this.status = 'resolved'
// this.resolveList.forEach(fn =>
// fn(this.value))
}
}
let reject = (err) => {
if (this.status === 'pending') {
this.reason = err
this.status = 'rejected'
// this.rejectList.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let that = this,x
if(that.status ==='resolved'){
onFulfilled(this.value)
}if (that.status === 'rejected') {
}
} 然后这个promise只能适用于简单的业务,如果我们是在异步方法中调用它的resolve方法,就必须先收集then上面的方法 当resolve方法调用时再让then方法执行
class PromiseHand {
constructor(executor) {
let that = this
this.value = undefined
this.reason = undefined
this.status = 'pending'
this.resolveList = []
this.rejectList = []
let resolve = (val) => {
if (this.status === 'pending') {
this.value = val
this.status = 'resolved'
this.resolveList.forEach(fn =>
fn(this.value))
}
}
let reject = (err) => {
if (this.status === 'pending') {
this.reason = err
this.status = 'rejected'
this.rejectList.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let that = this,x
if(that.status ==='resolved'){
onFulfilled(this.value)
}
if (that.status === 'rejected') {
onRejected(this.reason)
}
if(that.status === 'pending'){
this.resolveList.push(onFulfilled)
this.rejectList.push(onRejected)
}
}}然并卵,问题并没有那么简单,如果resolve返回的还是一个promise 我们在做链式调用也要处理传进来的promise,定义并使用resolvePromise处理这种情况。
class PromiseHand {
constructor(executor) {
let that = this
this.value = undefined
this.reason = undefined
this.status = 'pending'
this.resolveList = []
this.rejectList = []
let resolve = (val) => {
if (this.status === 'pending') {
this.value = val
this.status = 'resolved'
this.resolveList.forEach(fn =>
fn(this.value))
}
}
let reject = (err) => {
if (this.status === 'pending') {
this.reason = err
this.status = 'rejected'
this.rejectList.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let that = this,x
let promise2 = new PromiseHand((resolve, reject) => {
if (that.status === 'resolved') {
x = onFulfilled(this.value)
console.log(x)
resolvePromise(promise2, x, resolve, reject);
}
if (that.status === 'rejected') {
x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
}
if (that.status === 'pending') {
that.resolveList.push(() => {
x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject);
})
that.rejectList.push(() => {
x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject);
})
}
})
return promise2
}}
function resolvePromise(promise2, x, resolve, reject) {
// 不能返回自己
if (promise2 === x) {
return reject(new TypeError('mistake'))
}
let called; // 防止多次调用
// x返回的可能是对象和函数也可能是一个普通的值
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(x, y => {
if (called) return
called = true
// resolve的结果依旧是promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就失败了
})
}else{
resolve(x)
}
} catch (error) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(error);
}
} else {
resolve(x)
}}接下来实现以下all和race ,all方法可以说是Promise中很常用的方法了,它的作用就是将一个数组的Promise对象放在其中,当全部resolve的时候就会执行then方法,当有一个reject的时候就会执行catch,并且他们的结果也是按着数组中的顺序来排放的,那么我们来实现一下。
race就是看哪个先执行完就直接resolve结束。
//all方法
PromiseHand.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}//race方法
PromiseHand.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
}
})
}3.call、apply和bind的实现
call,apply实现原理差不多只是传参不太一样,bind是需要返回一个函数,这个函数也有可能被new再次传参执行 并且new的优先级比较高,所以需要判断new的调用,还有一个特点就是bind调用的时候可以传参,调用之后生成的新的函数也可以传参,效果是一样的,所以这一块也要做处理 因为上面已经实现了apply,这里就借用一下,实际上不借用就是把代码copy过来
Function.prototype._call = function (obj,...args) {
console.log(args)
//给context新增一个独一无二的属性以免覆盖原有属性
const key = Symbol()
obj[key] = this
let result = obj[key](...args)
delete obj[key]
return result
}
Function.prototype._apply = function (obj,args) {
console.log(args)
const key = Symbol()
obj[key] = this
let result = obj[key](...args)
delete obj[key]
return result
}
Function.prototype._bind = function (obj,...args) {
const fn1 = this
let fn2 =function(...innerArgs){
if(this instanceof fn2){
return new fn1(...args,...innerArgs)
}
return fn1.apply(obj,[...args,...innerArgs])
}
return fn2
}4.柯里化的实现
function add(a,b,c){
return a+b+c
}
function curry(fn,...args){
let newargs=[]
return function next(...innerArgs){
newargs = [...innerArgs,...newargs]
console.log(newargs)
if(newargs.length<fn.length){
return next
}else{
return fn(...newargs)
}
}
}
var newAdd = curry(add)
console.log(newAdd(1)(2)(3)) //65.深拷贝的实现
深拷贝,浅拷贝常常是前端容易混淆的地方。常见的浅拷贝如
- 基本数据类型的赋值
- 引用数据类型赋值,浅拷贝,栈内存指向的内存地址一样
- Object.assign(),只能第一层维度深拷贝故也输入浅拷贝
- ...,展开运算符,和Object.assign()一样 需要再处理才能对深层次维度深拷贝
深拷贝我们常常会用到JSON.parse(JSON.stringify(obj)),这也是我们写业务代码经常用的
然后现在我们再代码写一版对引用类型的遍历赋值实现深拷贝
function deepClone(obj){
if(typeof obj !== "object"){
throw new Error('obj 不是一个对象!')
}
var newObj = Array.isArray(obj)?[]:{}
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] ==='object'){
newObj[key] = deepClone(obj[key])
}else{
newObj[key] = obj[key]
}
}
}
return newObj
}同样,也可以用Object.assign或者...去遍历处理深层次实现深拷贝。