简单记录一些之前遇到的题目。
- 1.写出trottle和debonce函数,
- 2.写出Number.MAX_VALUE相加函数
- 3.原生DOM写出拖拽效果
- 4.dfs算法
- 5.原生js写出eventEmitter
-
- 实现一个promise, (promise.all, Promise.race)。
-
- 实现一个reapeat 方法。
-
- 快速排序
-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
});
- 快速排序
// 简陋版本
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');
有兴趣的朋友, 可以补充答案到评论区。