new()方法
(1)__proto__ 指向 构造函数的原型
(2)通过apply改变this指向获取构造函数的属性和方法
(3) 如果构造函数执行的结果返回的是一个对象,那么返回这个对象
(4)不存在就返回对象
function _new(fun ){
var obj ={}
obj.__proto__ =fun.prototype
//var obj = Object.create(fun.prototype)//合并前面两步
var result = fun.aplly(obj)
if(obj && (typeof(obj)=='object' || typeof(obj) =='funtion') ){
return result
}
return obj
}
Object.create()
思路:将传入的对象作为原型function create(obj){
function F(){ }
F.proptotype= obj
return new F()
}function create(fun){
var obj ={} // new Object()
obj.__proto__ =fun.prototype // Object.prototype = fun.prototyperetrun obj
}
考虑下是否一样
intanceof
用于判断构造函数的proptotype是否出现在原型链的任何位置(1)首先获取类型的原型
(2)然后获得对象的原型
(2)然后一直循环判断对象的原型是否等于类型的原型,直到对象原型为
null,因为原型链最终为nullfunction instanceof( left,right){
var proto = Object.getProrotypeOf(left),
prototype = right.prototype;
while(true){
if(!proto) return false;
if(proto == prototype ) return true;
proto = Object.getPrototypeOf(prototype);}
}
Promise
new Promise(function(resolve,reejct){
setTimeout(funciton(){
console.log('1')
resolve("随便什么数据")})
})const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn){
//保存初始化状态var self = this
//初始化状态
this.state = PENDING// 用于保存resolve或者 rejected传入的值
this.value = null
//保存resolve的回调函数
this.resolvedCallbacks = []
//保存reject 的回调函数
this.rejectedCallbacks = []
//状态转变为 resolved方法
function resolve(value){// 判断传入元素是否为 Promise 值,如果是,则状态改变必须等到前一个状态改变后再进行改变
if(value instanceof MyPromise){
return value.then(resolve,reject)
}//保证代码的执行属性为本轮事件循环的的末尾
setTimeout(()=>{
// 只有状态为 PENDING
if(self.state === PENDING){
//修改状态
self.state = RESOLVED
//设置传入的值
self.value =value
self.resolvedCallbacks.forEach(callback =>{
callback(value)})
}
},0)
}
// 状态转变为 rejected 方法function reject(value){
//保证代码的执行属性为本轮事件循环的的末尾
setTimeout(()=>{
// 只有状态为 PENDING
if(self.state === PENDING){
//修改状态
self.state = REJECTED
//设置传入的值
self.value =value
self.rejectedCallbacks.forEach(callback =>{
callback(value)})
}
},0)
}// 将两个方式出入函数参数
try{
fn(resolve,reject)
}catch(e){
//遇到错误时,补货错误,执行reject 函数
reject(e)
}}
MyPromise.prototype.then = function(onResolved,onRejected){
//首先判断两个参数是否函数类型,因为这两个参数是可选参数
onResolved = typeof onResolved === function? onResolved:
funciont(value){ return value }
onRejected= typeof onRejected=== function? onRejected:
funciont(error){ throw error }
//如果是等待状态,则将函数加入对应的列表中
if(this.state === PENDING){
this.resolvedCallbacks.push (onResolved)
this.rejectedCallbacks.push(onRejected)
}
//如果状已经凝固 则直接执行对应状态的函数
if(this.state === RESOLVED){
onResolve(this.value)
}if(this.state === REJECTED){
onRejected(this.value)
}
}
Promise.then
- 连续多个
then里的回调方法是同步注册的,但注册到了不同的callbacks数组中,因为每次then都返回新的promise实例(参考上面的例子和图)- 注册完成后开始执行构造函数中的异步事件,异步完成之后依次调用
callbacks数组中提前注册的回调then(onFulfilled, onReject){
// 保存前一个promise的this
const self = this;
return new MyPromise((resolve, reject) => {
// 封装前一个promise成功时执行的函数
let fulfilled = () => {
try{
const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //启后
}catch(err){
reject(err)
}
}
// 封装前一个promise失败时执行的函数
let rejected = () => {
try{
const result = onReject(self.value);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){
reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
Promise.all 返回一个数组
其中一个接口失败了,多个也就失败了
function promiseAll(promises){
return new Promise(funciont(resolve,reject){
if(!Array.isArray(promises)){
throw new TypeError("arguments must be array ")}
var resolvedCounter =0
var promiseNum = promise.lengthvar resolvedResult = []
for(let i =0; iPromise.resolve(promises[i]).then(value=>{ resolvedCounter ++
resolvedResult[i] = value
if(resolvedCounter == promiseNum){
return resolve(resolvedResult)}
},error=>{
return reject(error)}
}
})
}let p1 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(1) }, 1000) }) let p2 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(2) }, 2000) }) let p3 = new Promise(function (resolve, reject) { setTimeout(function () { resolve(3) }, 3000) }) promiseAll([p3, p1, p2]).then(res => { console.log(res) // [3, 1, 2] })
Promise.race 谁先成功就用谁的状态
Promise.race = funciton (args){
return new Promise((resolve,reject)=>{
for(let i = 0 ; i< args.length;i++){
args[i].then(resolve,reject)}
})
}
防抖
函数防抖是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。function debounce(fn, wait) {
var time = nullreturn function(){
let context = this,args = arguments
if(time){clearTimeout(time)
time = null
}time= setTimeout(()=>{
fun.apply(context,args)},wait)
}
}function debounce(fn,wait=50,immediate){
val timer= null;
retrun function(){if (timer) clearTimeout(timer)
const self = thisif (immediate && !timer) {
fn.apply(this, arguments)
}
time = setTimeout(()=>{
fn.apply(self ,arguments)
timer=null
},wait)
}
}
节流
指定时间内执行,在指定时间内多次点击也只会执行一次,来降低事件频率。function throttle(fn,delay){
let curTime = Date.now();return function(){
let context = this,args = arguments,
nowTime = Date.now();
if(nowTime -curTime>=dalay){
curTime = Date.now()
return fn.apply(context,args)
}
}
}
判断函数
function getType(value){
if(value === null){
return value + " "
}
//Object Array
if(typeof value === "object"){
let valueClass = Object.prototype.toString.call(value),
type = valueClass.split(" ")[1].split("");//转成数组 第一个O 最后一个]
type.pop() //删除 ]
type.join("").toLowerCase() //将首字母小写
return type
}else{
// 判断数据是基本数据类型的情况和函数的情况
// string boolean number symbol undefined function
return typeof value;
}
}
call函数 数组
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 处理传入的参数,截取第一个参数后的所有参数。
- 将函数作为上下文对象的一个属性。
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性。
- 返回结果。
Function.prototype.myCall = function(context){
// 判断调用对象
if(typeof this !=="function"){
console.error("type error")
}
//获取参数
let args = [...arguments].slice(1),//去掉第一个参数 数组
result = null
//判断 context是否传入 ,未传入则传入window
context = context||window
// 将调用函数设为方法
context.fn = this// 调用函数
result = context.fn(...args)
// 将属性删除
delete context.fn
return result //返回的执行结果
}
apply函数
- 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
- 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
- 将函数作为上下文对象的一个属性。
- 判断参数值是否传入
- 使用上下文对象来调用这个方法,并保存返回结果。
- 删除刚才新增的属性
- 返回结果
Function.prototype.myApply = function(context){
//判断调用对象是否为函数
if(type this !== "function"){throw new TypeError("Error")
}
let context = context || window,result = null
context.fn = thisif(arguments[1]){
result = context.fn(...arguments[1])}else{
result = context.fn()}
delete context.fn
return result
}
bind
Function.prototype.bind = function(){
let args = Arrary.prototype.slice(arguments) //转化成可操作数组
let t = args.shift() // 分割 args 并返回第一个参数
const self = this :
return function(){
return self.apply(t, args)}
}
function fun1(a,b,c){
console.log(this) // {name:"obj"}
console.log(a,b,c) //10,20,30
}
var obj = {
name:"obj"
}
var fun = fun1.bind(obj,10,20,30)
fun()
promise封装Post请求-缺
深拷贝
浅拷贝-没有深入拷贝,或者只拷贝了属性
funciton deppClone(object){
if( !object || typeof object !==''object"){
return object}
let newObject = Array.isArray(object) ? [] :{}
for(let key in object){if(object.hasOwnProperty(key)){ //对象自己的属性,过滤掉原型链上的属性
newObject[key] = typeof object[key] =='object' ?deepClone( object[key]) : object[key]
}
}return newObject
}
时间的格式化
dataFormat('2020-10-11','yyyy-MM-dd')dataFormat('2020-10-11','yyyy/MM/dd')
function dataFormat(dateInpue,format){const currentDate = new Date(dateInpue)
const day = currentDate.getDate()const month = currentDate.getMonth() +1
const year = currentDate.getFullYear()
format.replace(/yyyy/,year)
format.replace(/MM/,month )
format.replace(/dd/,day )
return format
}
两个数字变量不通过临时变量实现值互换
a b
a = a + b
b= a - b //原来的a
a= a -b //原来的b
两个数字求和
var a = [1,2,3,4,5,6,,7,8,9]
(1)方法一for循环
(2)reduce
var num = a.reduce((sum,current,index)=>{return sum = sum + current
},0)
(3)递归
function add (a){
if(a.length==0){return 0
}
if(a.length == 1) return a[0]
return a[0] + add(a.slice(1))
}
数组扁平化
let arr = [1, [2, [3, 4]]];
(1)array.tostring().split(',')
(2)flat(层数)
arry.flat(3)
(3)递归遍历
(4)reducefunciont flatArray(arry)
arry.reduce(function(prev,next){return prev.concat(Array.isArray(next)? flatArray(next):next)
},[])
}(5) while some
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
(6正则
function flatten(arr) {
let str = JSON.stringify(arr);
str = str.replace(/()/g, '');" role="presentation" style="text-align: center; position: relative;"> |
str = '[' + str + ']';
return JSON.parse(str);
}
数组去重
const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
(1)遍历
(2)Array.from(new Set(array ))
(3)属性 使用 Object.hasOwnPropety()
{1:1,2:1,3:1,9:1}
这种方式
实现数组的flat方法
function _flat(arry,depth){
if(Array.isArray(arry) || depth<=0 ){
return arry}
arry.reduce((prev,next)=>{
if(Array.isArray(next)){
return prev.concat(_flat(next))
}else{
prev.push(next)
}
},[])
}
实现数组的push方法
let arr = []
Array.prototype.push = function(){
for(let i , ithis[this.length] = arguments[i]
}
return this.length
}
实现数组的filter
fn返回是true falseArray.prototype.filter = funciton(fn){
if(typeof this !== 'function'){
return console.log(‘必须为函数’)}
const res = []for(let i=0,len = this.length; i
fn(this[i]) && res.push(this[i])
}return res
}
实现数组的map函数
Array.prototype.map = function(fn){if(typeof this !== 'function'){
return console.log(‘必须为函数’)}
const res = []
for(let i=0,len = this.length; ires.push(fn(this[i]))
}return res
}
字符串添加翻转
Array.prototype._reverse= function(){
return this.split('').reverse.join('')
}
中间还有很多
。。。。。。
实现Jsonp
function addScript(url){
const script= document.createElement('script')script.src = url
script.type = 'text/javascirpt'
document.body.appendChild(script)
}
addScript("http://xxx.xxx.com/xxx.js?callback=handleRes");
// 设置一个全局的callback函数来接收回调结果
function handleRes(res) {
console.log(res);
}
// 接口返回的数据格式
handleRes({a: 1, b: 2});
实现发布式订阅
class EventCenter{
// 1. 定义事件容器,用来装事件数组
let handlers = {}// 2. 添加事件方法,参数:事件名 事件方法
addEventListener(type, handler) {
// 创建新数组容器
if (!this.handlers[type]) {
this.handlers[type] = []
}
// 存入事件
this.handlers[type].push(handler)
}// 3. 触发事件,参数:事件名 事件参数
dispatchEvent(type, params) {
// 若没有注册该事件则抛出错误
if (!this.handlers[type]) {
return new Error('该事件未注册')
}
// 触发事件
this.handlers[type].forEach(handler => {
handler(...params)
})
}// 4. 事件移除,参数:事件名 要删除事件,若无第二个参数则删除该事件的订阅和发布
removeEventListener(type, handler) {
if (!this.handlers[type]) {
return new Error('事件无效')
}
if (!handler) {
// 移除事件
delete this.handlers[type]
} else {
const index = this.handlers[type].findIndex(el => el === handler)
if (index === -1) {
return new Error('无该绑定事件')
}
// 移除事件
this.handlers[type].splice(index, 1)
if (this.handlers[type].length === 0) {
delete this.handlers[type]
}
}
}
}