js手写面试题

防抖

  function debounce(func, wait) {
        let timeout;
        return function () {
            const context = this;
            if (timeout) clearTimeout(timeout);
            timeout = setTimeout(() => {
                func.call(context, arguments)
            }, wait);
        }
    }

节流

     function throttle(func, wait) {
        var previous = 0;
        return function() {
            let now = Date.now();
            let context = this;
            if (now - previous > wait) {
                 func.call(context, arguments);
                 previous = now;
            }
        }

手写一个Promise

三种状态pending| fulfilled(resolved) | rejected
当处于pending状态的时候,可以转移到fulfilled(resolved)或者rejected状态
当处于fulfilled(resolved)状态或者rejected状态的时候,就不可变。

promise特征:

1 立即执行性。创建promise时,作为参数传入的函数被立刻执行。
2 3种状态。
3 状态不可改。
4 链式调用。

必须有一个then异步执行方法,then接受两个参数且必须返回一个promise:

// onFulfilled 用来接收promise成功的值
// onRejected 用来接收promise失败的原因
promise1=promise.then(onFulfilled, onRejected);

用法:

var promise = new Promise((resolve,reject) => {
    if (操作成功) {
        resolve(value)
    } else {
        reject(error)
    }
})
promise.then(function (value) {
    // success
},function (value) {
    // failure
})
  function myPromise(constructor){
        let self=this;
        self.status="pending" //定义状态改变前的初始状态
        self.value=undefined;//定义状态为resolved的时候的状态
        self.reason=undefined;//定义状态为rejected的时候的状态
        function resolve(value){
            //两个==="pending",保证了状态的改变是不可逆的
            if(self.status==="pending"){
                self.value=value;
                self.status="resolved";
            }
        }
        function reject(reason){
            //两个==="pending",保证了状态的改变是不可逆的
            if(self.status==="pending"){
                self.reason=reason;
                self.status="rejected";
            }
        }
        //捕获构造异常
        try{
            constructor(resolve,reject);
        }catch(e){
            reject(e);
        }
    }
    
    myPromise.prototype.then = function(onFullfilled,onRejected) {
        let self = this
        switch(self.status){
            case 'resolved':
                onFullfilled(self.value)
                break
            case 'rejected':
                onRejected(self.reason)
                break
            default:
                break
        }
    }
    var p = new Promise(function(resolve,reject) {resolve(1)})
    p.then(function(x){console.log(x)})

实现一个链式调用


new Promise((resolve,reject)=>{
   console.log('1')
   resolve('2')
}).then(res=>{
   console.log(res)
   return new Promise((resolve,reject)=>{
       reject(new Error('4'))
   })
}).then(res=>{
   console.log(res)
}).catch(e=>console.log(e))

promiseAll

function PromiseAll(proArray) {
    return new Promise((resolve,reject)=>{/////返回一个promise
        if(!Array.isArray(proArray)) {
            return reject(new Error('输入数组'))//new error
        }
        var len = proArray.length
        let count = 0
        var arr=[]
        for(let i=0;i<len;i++) {////let
            Promise.resolve(proArray[i]).then((res)=>{
                arr[i] = res
                count++
                if (count == len) {
                    resolve(arr)
                }
            }).catch(e => reject(e))
        }
    })
}

const pro1 = new Promise((res,rej) => {
    setTimeout(()=>{
        res('1')
    },1000)
})
const pro2 = new Promise((res,rej) => {
    setTimeout(()=>{
        res('2')
    },2000)
})
const pro3 = new Promise((res,rej) => {
    setTimeout(()=>{
        res('3')
    },3000)
})
const proAll = PromiseAll([pro1,pro2,pro3])
    .then(res =>
        console.log(res)
    )
    .catch((e) =>{
        console.log(e)
    })

js实现一个深拷贝

       var obj = {
            a:1,
            b: [2,3,4],
            c: true,
            d: function() {
                console.log('5')
            },
            e: new RegExp('\\w+')
        }
       var obj1 = JSON.parse(JSON.stringify(obj))
       console.log('obj1',obj1)

如果obj里面有时间对象,正则,函数,都不能正确拷贝

     function deepCopy(obj){
         //判断是否是简单数据类型,
         if(typeof obj == "object"){
              //复杂数据类型
              var result = obj.constructor == Array ? [] : {};
              for(let i in obj){
                 result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
              }
          }else {
              //简单数据类型 直接 == 赋值
              var result = obj;
          }
            return result;
        }

instanceOf

检测对象A是不是另一个对象B的实例的原理是:查看对象B的prototype属性指向的原型对象是否在对象A的原型链上,若在则返回true,若不在则返回false。

      function instanceOf(left,right) {
            let proto = left.__proto__;
            let prototype = right.prototype
            while(true) {
                if(proto === null) return false
                if(proto === prototype) return true
                proto = proto.__proto__;
            }
        }
let arr = []
let obj = {}
arr instanceof Array    // true
arr instanceof Object   // true
obj instanceof Object   // true
obj instanceof Array   // false

arr 数组相当于 new Array() 出的一个实例,所以 arr.proto === Array.prototype,又因为 Array属于 Object 子类型,即 Array.prototype.proto === Object.prototype.
因此 Object 构造函数在 arr 的原型链上。
所以 instanceof 仍无法判断一个值到底属于数组还是普通对象。

Object.prototype.toString()

Object.prototype.toString.call({})              
// '[object Object]'
Object.prototype.toString.call([])              
// '[object Array]'
Object.prototype.toString.call(() => {})        
// '[object Function]'
Object.prototype.toString.call('wangergou')        
// '[object String]'
Object.prototype.toString.call(null)            
// '[object Null]'
Object.prototype.toString.call(undefined)       
// '[object Undefined]'

call,apply,bind

       Function.prototype.call = function (context, ...args) {
           context = context || window;
           context.fn = this;
           let result = eval('context.fn(...args)');
           delete context.fn
           return result;
       }
        Function.prototype.apply = function (context, args) {
            context = context || window;
            context.fn = this;
            let result = eval('context.fn(...args)');
            delete context.fn
            return result;
        }
        Function.prototype.ownBind = function(context) {
            context = context || window;
            return (...args)=>{
                this.call(context, ...args)
            }
        }

实现Object.create方法

        let demo = {
            c : '123'
        };
        let cc = Object.create(demo);
        console.log(cc);    

        function create(proto) {
            function Fn() {};
            // 将Fn的原型指向传入的 proto
            Fn.prototype = proto;
            Fn.prototype.constructor = Fn;
            return new Fn();
        };

函数实现柯里化

function sum(a, b, c, d, e) {
  return a+b+c+d+e;
};

let a = curring(sum)(1,2)(3,4)(5);
console.log(a); // 15
     const curring = (fn, arr = []) => {
            let len = fn.length;
            return function (...args) {
                arr = [...arr, ...args];
                if (arr.length < len) {
                    return curring(fn, arr);
                } else {
                    return fn(...arr);
                }
            };
     };

拍平

Array.prototype.flat() 特性总结

Array.prototype.flat() 用于将嵌套的数组“拉平”,变成一维的数组。
该方法返回一个新数组,对原数据没有影响。
不传参数时,默认“拉平”一层,可以传入一个整数,表示想要“拉平”的层数。
传入 <=0 的整数将返回原数组,不“拉平”
Infinity 关键字作为参数时,无论多少层嵌套,都会转为一维数组
如果原数组有空位,Array.prototype.flat() 会跳过空位。

用 reduce 实现 flat 函数

const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "弹铁蛋同学" }]

// 首先使用 reduce 展开一层
arr.reduce((pre, cur) => pre.concat(cur), []);
// [1, 2, 3, 4, 1, 2, 3, [1, 2, 3, [1, 2, 3]], 5, "string", { name: "弹铁蛋同学" }];

// 用 reduce 展开一层 + 递归
const flat = arr => {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flat(cur) : cur);
  }, []);
};
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];

通过传入整数参数控制“拉平”层数

// reduce + 递归
function flat(arr, num = 1) {
  return num > 0
    ? arr.reduce(
        (pre, cur) =>
          pre.concat(Array.isArray(cur) ? flat(cur, num - 1) : cur),
        []
      )
    : arr.slice();
}
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]], 5, "string", { name: "弹铁蛋同学" }]
flat(arr, Infinity);
// [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3, 5, "string", { name: "弹铁蛋同学" }];

手写一个reduce

//实现一个reduce
Array.prototype.reduce = function(fn, init){
    var arr = this
    var total = init || arr[0]
    for(var i=init?0:1; i<arr.length; i++){
        total = fn(total,arr[i],i,arr)
    }
    return total
}
var arr = [1,2,3]
console.log(arr.reduce((prev,item)=>prev+item,10))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • 今年来,各大公司都缩减了HC,甚至是采取了“裁员”措施,在这样的大环境之下,想要获得一份更好的工作,必然需要付出更...
    Vicky丶Amor阅读 1,909评论 1 65
  • 2.什么是函数柯里化? 答:是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接...
    Rain_Wuu阅读 2,231评论 1 8
  • 数值的扩展 date:(2019.07.17) 二进制和八进制表示法 Number.isFinite(), Num...
    洛音轩阅读 277评论 0 0
  • 1. 说一下对HTML语义化的理解? 语义化就是选择与语义相符合的标签,使代码语义化,这样不仅便于开发者进行阅读,...
    陈二狗想吃肉阅读 2,110评论 3 16
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,504评论 28 53