几道题

简单记录一些之前遇到的题目。

  • 1.写出trottle和debonce函数,
  • 2.写出Number.MAX_VALUE相加函数
  • 3.原生DOM写出拖拽效果
  • 4.dfs算法
  • 5.原生js写出eventEmitter
    1. 实现一个promise, (promise.all, Promise.race)。
    1. 实现一个reapeat 方法。
    1. 快速排序
      -9 DeepClone

  Function.prototype.mybind = function(context) {
    return () => this.call(context);
  }

写一个通用的事件侦听器函数
// event(事件)工具集,来源:github.com/markyun

    markyun.Event = {
       
        // 视能力分别使用dom0||dom2||IE方式 来绑定事件
        // 参数: 操作的元素,事件名称 ,事件处理程序
        addEvent : function(element, type, handler) {
            if (element.addEventListener) {
                //事件类型、需要执行的函数、是否捕捉
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent('on' + type, function() {
                    handler.call(element);
                });
            } else {
                element['on' + type] = handler;
            }
        },
        // 移除事件
        removeEvent : function(element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.datachEvent) {
                element.detachEvent('on' + type, handler);
            } else {
                element['on' + type] = null;
            }
        },
        // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
        stopPropagation : function(ev) {
            if (ev.stopPropagation) {
                ev.stopPropagation();
            } else {
                ev.cancelBubble = true;
            }
        },
        // 取消事件的默认行为
        preventDefault : function(event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },
        // 获取事件目标
        getTarget : function(event) {
            return event.target || event.srcElement;
        }

三位加逗号

'1234567'.replace(/\B(?=(?:\d{3})+\b)/g, ',');
// 1234567 => '1,234,567'



// 处理数字
let str1 = 2123456789;
let str2 = 2123456789.12;
console.log(str1.toLocaleString()); // 2,123,456,789


    // 处理字符串
    let str1 = '2123456789';
    let str2 = '2123456789.12';

    // 利用正向预查 匹配 开头一个数字\d 后面匹配这个数字后面必须是三个数字为一组为结尾或小数为结尾
    function thousandth(str) { 
        let reg = /\d(?=(?:\d{3})+(?:\.\d+|$))/g; 
        return str.replace(reg, '$&,');
    }
    console.log(thousandth(str1)); // 2,123,456,789

// 写出trottle和debonce函数;
// 乞丐版
var throttle = function(delay, action) {
var last = 0;
return function(){
    var curr = +new Date()
    if (curr - last > delay){
      action.apply(this, arguments)
      last = curr 
    }
  }
}


// throttle 也接收两个参数: 一个实际要执行的函数 fn,一个执行间隔阈值 threshhold。
    function throttle(fn, threshhold) {
        var last, timer;
        threshhold || (threshhold  = 300);
        return function() {
        var context = this;
        var args = arguments;
        var now = +new Date();
        if(last && now < last + threshhold) {
            clearTimeout(timer);
            timer = setTimeout(()=> {
                last = now;
                fn.apply(context, args);
            }, threshhold);
        } else {

            last = now;
            fn.apply(context, args);
        }
    }
}

function debounce(fn, delay){
    var timer;
     // delay || (delay = 500);
    return function(){
        var context = this;
        var args = arguments;
        clearTimeout(timer);

        timer = setTimeout(function(){
            fn.apply(context, args);
        }, delay)
    }
}

document.addEventListener('mousemove', debounce(function(e){
    console.log('move');
}, 1000));
// 写出Number.MAX_VALUE相加函数
var BigInt = function (str) {
 // your code here
   
};

BigInt.prototype.plus = function (bigint) {
 // your code here
 
 return this.toString(result);  
};

BigInt.prototype.toString = function (result) {
 // your code here
 
};

var bigint1 = new BigInt('1234232453525454546445451434342153453454545454545454');
var bigint2 = new BigInt('1234232453525454546445451434342153453454545454545454');

console.log(bigint1.plus(bigint2));


// 一种解法:

var BigInt = function (str) {
  // your code here
    var strArr = str.split("")
    strArr.plus = this.plus
    strArr.toString = this.toString
    return strArr;
 };
 
 BigInt.prototype.plus = function (bigint) {
  // your code here
  const arr = []
  const distance = bigint.length - this.length
  //补位
  if(distance > 0){
    for(let i = 0; i < distance; i++){
      this.unshift('0');
    }
  }else{
    for(let i = 0; i < -distance; i++){
      bigint.unshift('0');
    }
  }
  // > 10 进位为1 否则为0
  let step = 0;
  let result = bigint.map((item, index) => {
    let temp = (+item) + (+this[index]) + step;
    if(temp > 10){
      step = 1;
      return (temp + '')[0]
    }else{
      step = 0;
      return temp
    }
  })
  return this.toString(result);  
 };
 
 BigInt.prototype.toString = function (result) {
  // your code here
  return result.join("");
 };
 
 var bigint1 = new BigInt('1234232453525454546445451434342153453454545454545454');
 var bigint2 = new BigInt('1234232453525454546445451434342153453454545454545454');
 
 console.log(bigint1.plus(bigint2)); 
// 24684648106104108108108198108102868684210681068108108108108108108108

// 原生DOM写出拖拽效果
// 基本思路如下:

拖拽状态 = 0鼠标在元素上按下的时候{      
    拖拽状态 = 1      
    记录下鼠标的x和y坐标      
    记录下元素的x和y坐标      
   }   
 鼠标在元素上移动的时候{      
    如果拖拽状态是0就什么也不做。      
    如果拖拽状态是1,那么      
    元素y = 现在鼠标y - 原来鼠标y + 原来元素y      
    元素x = 现在鼠标x - 原来鼠标x + 原来元素x      
    }       
 鼠标在任何时候放开的时候{      
    拖拽状态 = 0      
} 


**********
window.onload = function() { //拖拽功能(主要是触发三个事件:onmousedown\onmousemove\onmouseup) var drag = document.getElementById('drag'); //点击某物体时,用drag对象即可,move和up是全局区域,也就是整个文档通用,应该使用document对象而不是drag对象(否则,采用drag对象时物体只能往右方或下方移动) drag.onmousedown = function(e) { var e = e || window.event; //兼容ie浏览器 var diffX = e.clientX - drag.offsetLeft; //鼠标点击物体那一刻相对于物体左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离 var diffY = e.clientY - drag.offsetTop; /*低版本ie bug:物体被拖出浏览器可是窗口外部时,还会出现滚动条, 解决方法是采用ie浏览器独有的2个方法setCapture()\releaseCapture(),这两个方法, 可以让鼠标滑动到浏览器外部也可以捕获到事件,而我们的bug就是当鼠标移出浏览器的时候, 限制超过的功能就失效了。用这个方法,即可解决这个问题。注:这两个方法用于onmousedown和onmouseup中*/ if(typeof drag.setCapture!='undefined'){ drag.setCapture(); } document.onmousemove = function(e) { var e = e || window.event; //兼容ie浏览器 var left=e.clientX-diffX; var top=e.clientY-diffY; //控制拖拽物体的范围只能在浏览器视窗内,不允许出现滚动条 if(left<0){ left=0; }else if(left >window.innerWidth-drag.offsetWidth){ left = window.innerWidth-drag.offsetWidth; } if(top<0){ top=0; }else if(top >window.innerHeight-drag.offsetHeight){ top = window.innerHeight-drag.offsetHeight; } //移动时重新得到物体的距离,解决拖动时出现晃动的现象 drag.style.left = left+ 'px'; drag.style.top = top + 'px'; }; document.onmouseup = function(e) { //当鼠标弹起来的时候不再移动 this.onmousemove = null; this.onmouseup = null; //预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动) //修复低版本ie bug if(typeof drag.releaseCapture!='undefined'){ drag.releaseCapture(); } }; }; };
// dfs算法
function dfs(tree, name){
 // 请在这里实现
 let i = 0;
 let targetObj;
 const keys = Object.keys(tree.children || {});
 while( i < keys.length) {
    if(tree.children[keys[i]].name === name) {
        targetObj = tree.children[keys[i]];
        console.log(targetObj);
        break;
    }
    dfs(tree.children[keys[i]], name);
    i += 1;
 }
 console.log(targetObj);
 return targetObj ;

}

var tree = {
 name : '中国',
 children : [
  {
   name : '北京',
   children : [
    {
     name : '朝阳群众'
    },
    {
     name : '海淀区'
    },
                {
     name : '昌平区'
    }
   ]
  },
  {
   name : '浙江省',
   children : [
    {
     name : '杭州市',
     code : 0571,
    },
    {
     name : '嘉兴市'
    },
    {
     name : '绍兴市'
    },
    {
     name : '宁波市'
    }
   ]
  }
 ]
};

var node = dfs(tree, '杭州市');
console.log(node);    // { name: '杭州市', code: 0571 }
// 原生js写出eventEmitter

     document.getElementById('submit').onclick = function() {  
     /*  
        var emit = new EventEmitter();  
          
        emit.on('click', function() {  
          console.log('clcik');  
        }, 2);  
        emit.trigger('click');  
        emit.trigger('click');  
        emit.trigger('click');  
     */  
     var Target = function(){};  
     EventEmitter.inherit(Target);  
     var test = new Target();  
      test.on('click', function() {  
          console.log('clcik');  
        }, 2);  
         test.trigger('click');  
         test.trigger('click');  
  
     };  

;(function (window, undefined) {
    'use strict';
    /*构造函数*/
    var EventEmitter = function() {
        this.events = {};//保存事务,存储结构为{'eventName1':[{listener:function触发的函数, time:触发的次数}], 'eventName2':[],}
    };
    
    EventEmitter.prototype.once = function(evt, listener) {
         return this.addListener(evt, listener, 0);
    };
    /*获取所有的事务*/
    EventEmitter.prototype.getEvents = function() {
        return this.events || (this.events = {});
    }
    /*获取某个实践的所有触发函数*/
    EventEmitter.prototype.getListeners = function(evt) {
         var events = this.getEvents();
         return events[evt] || (events[evt] = []);
    };
    /**
      注册实践触发函数
      evet:事件名称
      listener:事件监听函数
      time:可选,选择可以触发的次数,-1表示无数次,默认为-1
    **/
    EventEmitter.prototype.on = function(evt, listener, time) {
        time = typeof(time) == 'number' ? time : -1;
        time = time >= -1 ? time : -1; 
        var listeners = this.getListeners(evt);
        var listenerWrapper = {
            listener:listener,
            time:time,
        };
        listeners.push(listenerWrapper);
        
        return this;
    };
    /*addListener 和on 同义 */
    EventEmitter.prototype.addListener = EventEmitter.prototype.on;
    /*移除事件的所有监听函数*/
    EventEmitter.prototype.off = function(evt) {
        var events = this.getEvents();
        events[evt] = [];
    };
    EventEmitter.prototype.removeEvent = EventEmitter.prototype.off;
    
    /**
      会删除同一事件中的所有listener
    **/
    EventEmitter.prototype.removeListener = function(evt, listener) {
        var listeners = this.getListeners(evt);
        for(var i=0; i

实现一个promise, (promise.all, Promise.race)。


//完整版,代码后面附有实例,方便检验

(function(window,undefined){

// resolve 和 reject 最终都会调用该函数
var final = function(status,value){
    var promise = this, fn, st;
        
    if(promise._status !== 'PENDING') return;
    
    // 所以的执行都是异步调用,保证then是先执行的
    setTimeout(function(){
        promise._status = status;
        st = promise._status === 'FULFILLED'
        queue = promise[st ? '_resolves' : '_rejects'];

        while(fn = queue.shift()) {
            value = fn.call(promise, value) || value;
        }

        promise[st ? '_value' : '_reason'] = value;
        promise['_resolves'] = promise['_rejects'] = undefined;
    });
}


//参数是一个函数,内部提供两个函数作为该函数的参数,分别是resolve 和 reject
var Promise = function(resolver){
    if (!(typeof resolver === 'function' ))
        throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
    //如果不是promise实例,就new一个
    if(!(this instanceof Promise)) return new Promise(resolver);

    var promise = this;
    promise._value;
    promise._reason;
    promise._status = 'PENDING';
    //存储状态
    promise._resolves = [];
    promise._rejects = [];
    
    //
    var resolve = function(value) {
        //由於apply參數是數組
        final.apply(promise,['FULFILLED'].concat([value]));
    }

    var reject = function(reason){
        final.apply(promise,['REJECTED'].concat([reason]));
    }
    
    resolver(resolve,reject);
}

Promise.prototype.then = function(onFulfilled,onRejected){
    var promise = this;
    // 每次返回一个promise,保证是可thenable的
    return new Promise(function(resolve,reject){
        
        function handle(value) {
            // 這一步很關鍵,只有這樣才可以將值傳遞給下一個resolve
            var ret = typeof onFulfilled === 'function' && onFulfilled(value) || value;

            //判断是不是promise 对象
            if (ret && typeof ret ['then'] == 'function') {
                ret.then(function(value) {
                    resolve(value);
                }, function(reason) {
                    reject(reason);
                });
            } else {
                resolve(ret);
            }
        }

        function errback(reason){
            reason = typeof onRejected === 'function' && onRejected(reason) || reason;
            reject(reason);
        }

        if(promise._status === 'PENDING'){
            promise._resolves.push(handle);
            promise._rejects.push(errback);
        }else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行
            callback(promise._value);
        }else if(promise._status === REJECTED){
            errback(promise._reason);
        }
    });
}

Promise.prototype.catch = function(onRejected){
    return this.then(undefined, onRejected)
}

Promise.prototype.delay = function(ms,value){
    return this.then(function(ori){
        return Promise.delay(ms,value || ori);
    })
}

Promise.delay = function(ms,value){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve(value);
            console.log('1');
        },ms);
    })
}

Promise.resolve = function(arg){
    return new Promise(function(resolve,reject){
        resolve(arg)
    })
}

Promise.reject = function(arg){
    return Promise(function(resolve,reject){
        reject(arg)
    })
}

Promise.all = function(promises){
    if (!Array.isArray(promises)) {
        throw new TypeError('You must pass an array to all.');
    }
    return Promise(function(resolve,reject){
        var i = 0,
            result = [],
            len = promises.length,
            count = len
            
        //这里与race中的函数相比,多了一层嵌套,要传入index
        function resolver(index) {
          return function(value) {
            resolveAll(index, value);
          };
        }

        function rejecter(reason){
            reject(reason);
        }

        function resolveAll(index,value){
            result[index] = value;
            if( --count == 0){
                resolve(result)
            }
        }

        for (; i < len; i++) {
            promises[i].then(resolver(i),rejecter);
        }
    });
}

Promise.race = function(promises){
    if (!Array.isArray(promises)) {
        throw new TypeError('You must pass an array to race.');
    }
    return Promise(function(resolve,reject){
        var i = 0,
            len = promises.length;

        function resolver(value) {
            resolve(value);
        }

        function rejecter(reason){
            reject(reason);
        }

        for (; i < len; i++) {
            promises[i].then(resolver,rejecter);
        }
    });
}

window.Promise = Promise;

})(window);

/**********************************************************************/
//实例
var getData100 = function(){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('100ms');
        },1000);
    });
}

var getData200 = function(){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            resolve('200ms');
        },2000);
    });
}
var getData300 = function(){
    return new Promise(function(resolve,reject){
        setTimeout(function(){
            reject('reject');
        },3000);
    });
}

getData100().then(function(data){
    console.log(data); // 100ms
    return getData200();
}).then(function(data){
    console.log(data); // 200ms
    return getData300();
}).then(function(data){
    console.log(data); // 100ms
}, function(data){
    console.log(data);
});

Promise.all([getData100(), getData200()]).then(function(data){
    console.log(data); // 100ms
});

Promise.race([getData100(), getData200(), getData300()]).then(function(data){
    console.log(data); // 100ms
});
  1. 快速排序

// 简陋版本

function quickSort(arr) {
            if (arr.length <= 1) { return arr; } 
            var pivotIndex = Math.floor(arr.length / 2); 
            var pivot = arr[pivotIndex];  
            var left = [];
            var right = [];
            for (var i = 0; i < arr.length; i++) {
                if(i!== pivotIndex){
                    if (arr[i] > pivot) {
                        right.push(arr[i]);
                    } else {
                        left.push(arr[i]);
                    }
                }
            }
            return quickSort(left).concat([pivot],quickSort(right));
  }

进阶版:

const sort = (function() {
  // 默认状态下的比较函数
  function compare(a, b) {
    if (a === b) {
      return 0;
    }
    return a < b ? -1 : 1;
  }
  // 原地交换函数,而非用临时数组
  function swap(array, a, b) {
    [array[a], array[b]] = [array[b], array[a]];
  }

  // 分治函数
  function partition(array, left, right) {
    // 用index取中间值而非splice
    const pivot = array[Math.floor((right + left) / 2)];
    let i = left;
    let j = right;

    while (i <= j) {
      while (compare(array[i], pivot) === -1) {
        i++;
      }
      while (compare(array[j], pivot) === 1) {
        j--;
      }
      if (i <= j) {
        swap(array, i, j);
        i++;
        j--;
      }
    }
    return i;
  }
  // 快排函数
  function quick(array, left, right) {
    let index;
    if (array.length > 1) {
      index = partition(array, left, right);
      if (left < index - 1) {
        quick(array, left, index - 1);
      }
      if (index < right) {
        quick(array, index, right);
      }
    }
    return array;
  }
  return function quickSort(array) {
    return quick(array, 0, array.length - 1);
  };
})();

const arr = [2,5,3,7,6,1]

sort(arr)
function deepClone(o1, o2) {
    for (let k in o2) {
        if (typeof o2[k] === 'object') {
            o1[k] = {};
            deepClone(o1[k], o2[k]);
        } else {
            o1[k] = o2[k];
        }
    }
}
// 测试用例
let obj = {
    a: 1,
    b: [1, 2, 3],
    c: {}
};
let emptyObj = Object.create(null);
deepClone(emptyObj, obj);
console.log(emptyObj.a == obj.a);
console.log(emptyObj.b == obj.b);...
let arr = [[1, 2], 3, [[[4], 5]]]; // 数组展平
function flatten(arr) {
    return [].concat(
        ...arr.map(x => Array.isArray(x) ? flatten(x) : x)
    )
}
function CodingMan(name) { // 主要考察的是 面向对象以及JS运行机制(同步 异步 任务队列 事件循环)
    function Man(name) {
        setTimeout(() => { // 异步
            console.log(`Hi! This is ${name}`);
        }, 0);
    }

    Man.prototype.sleep = function(time) {
        let curTime = new Date();
        let delay = time * 1000;
        setTimeout(() => { // 异步
            while (new Date() - curTime < delay) {} // 阻塞当前主线程
            console.log(`Wake up after ${time}`);
        }, 0);
        return this;
    }

    Man.prototype.sleepFirst = function(time) {
        let curTime = new Date();
        let delay = time * 1000;
        while (new Date() - curTime < delay) {} // 阻塞当前主线程
        console.log(`Wake up after ${time}`);
        return this;
    }

    Man.prototype.eat = function(food) {
        setTimeout(() => { // 异步
            console.log(`Eat ${food}~~`);
        }, 0)
        return this;
    }

    return new Man(name);
}

// CodingMan('Peter');
// CodingMan('Peter').sleep(3).eat('dinner');
// CodingMan('Peter').eat('dinner').eat('supper');
// CodingMan('Peter').sleepFirst(5).eat('supper');

有兴趣的朋友, 可以补充答案到评论区。

你可能感兴趣的:(几道题)