个人去面试时。有时会遇到一些手写代码题。
花了点时间来总结一下,希望对大家有所帮助。
1,call的模拟实现
Function.prototype.myCall = function(context, ...rest){
context = context || window;
let fn = this;
context.fn = fn;
context.fn(...rest);
delete context.fn;
}
// 简单测试
let obj = {
name: '彭彭彭'
};
function test(){
console.log('arguments=',arguments); // Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log('this=',this); // {name: "彭彭彭", fn: ƒ}
}
test.myCall(obj,1,2);
复制代码
call的作用:
- 改变调用方法的this指向,使函数的this和传入的context的作用域保持一致,常用来封装一些方法或者做一些源码框架比较常用。
- 检测类型,Object.prototype.toString.call(type)。call配合toString可以用来判断变量类型。
2,apply的模拟实现
Function.prototype.myCall = function(context, ...rest){
context = context || window;
let fn = this;
context.fn = fn;
context.fn(rest); // 与call传参不一致。其他是一样的。就不详述了
delete context.fn;
}
复制代码
3,bind的模拟实现
Function.prototype.myBind = function(context, ...oldArg){
let cont = context || window;
let fn = this;
let emptyFn = function() {};
// 比call,apply多一个闭包而已。同时改变this的指向,延缓函数执行。
function newFn(...newArg){
var arg = [...oldArg, ...newArg];
return fn.apply(cont, arg);
}
// 继承老函数的原型方法
newFn.prototype = fn.prototype ? fn.prototype : emptyFn.prototype;
// 同时保持新函数原型的constructor不变
newFn.prototype.constructor = newFn;
return newFn;
}
复制代码
4,reduce的模拟实现
Array.prototype.myReduce = function(fn, initValue){
if(!this.length){
if(initValue) {
return initValue;
} else {
throw('error');
}
} else {
let startValue = initValue ? initValue : this[0];
let startIndex = initValue ? 1 : 0;
for(let i = 0; i < this.length; i++){
startValue = fn(startValue, this[startIndex]);
}
return startValue;
}
}
复制代码
5,deepCopy深拷贝的模拟实现
function checkType (type) {
return Object.prototype.toString.call(type).slice(8, -1);
}
function deepCopy(obj) {
let type = checkType(obj);
let newObj = null;
if (type === 'Object') {
newObj = {};
} else if(type === 'Array' ) {
newObj = [];
} else {
return obj;
}
for(let key in obj) {
let value = obj[key];
let valueType = checkType(value);
if (valueType === 'Array' || valueType === 'Object') {
arguments.callee(value);// 递归调用
} else {
if (!newObj.hasOwnProperty(value)) {
newObj[key] = value;
}
}
}
return newObj;
}
复制代码
6,debounce防抖的模拟实现
Function.prototype.myDebounce = function(cb, wait) {
let timer = null;
return function (...rest) {
if (timer) {
// 如果上次的定时器还存在,则清除。重新等待时间
clearTimeour(timer);
}
timer = setTimeout(() => {// 使用箭头函数,确保this还能定义在当前执行环境
// 里边的闭包的this必须保持和callback保持一致。确保使用ok
cb.apply(this, rest);
}, wait)
}
}
复制代码
7,throttle防抖的模拟实现
Function.prototype.myThrottle = function(cb, wait) {
let flag = false;
return function(...rest) {
if (flag) {
return;
}
flag = true;// 在wait时间范围内。。通过flag不让执行cb;
setTimeout(() => {
cb.apply(this, rest);
flag = false;
}, wait)
}
}
复制代码
8,两个无限大值想加的实现
// 如: 12341234123 + 32323423342
function infinite(a, b) {
let num = 0;
let str = '';
let aArr = a.split('');
let bArr = b.split('');
while(aArr.length || bArr.length || ) {
num += (~~aArr.pop()) + (~~b.Arr.pop());// 取个位相加
str = num + '';
num = num > 9; // true 转换为 1,我们借用 Js 的类型转换,完成了逻辑上的逢10进1操作。false时就不用进1
}
return str;
}
复制代码
9,获取cookie参数的实现
function getCookie(key) {
let arr;
let reg = new RegExp("(^| )" + key + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)) {
return unescape(arr[2]);
} else {
return null;
}
}
// 写入COOKIES
function $setCookie(name, value, expires, path, domain, secure) {
var exp = new Date();
expires = arguments[2] || null;
path = arguments[3] || '/';
domain = arguments[4] || null;
secure = arguments[5] || false;
expires ? exp.setMinutes(exp.getMinutes() + parseInt(expires)) : '';
document.cookie = name + '=' + escape(value) + (expires ? ';expires=' + exp.toGMTString() : '') + (path ? ';path=' + path : '') + (domain ? ';domain=' + domain : '') + (secure ? ';secure' : '');
}
// 删除cookie
function $delCookie(name, path, domain, secure) {
var value = $getCookie(name);
if (value != null) {
var exp = new Date();
exp.setMinutes(exp.getMinutes() - 1000);
path = path || '/';
document.cookie = name + '=;expires=' + exp.toGMTString() + (path ? ';path=' + path : '') + (domain ? ';domain=' + domain : '') + (secure ? ';secure' : '');
}
}
复制代码
10,获取url参数的实现
function $getQuery(name, url) {
var u = url || window.location.search;
var reg = new RegExp('(^|&)' + name + '=([^&#]*)(&|#|$)');
var r = u.substr(u.indexOf('?') + 1).match(reg);
return r != null ? r[2] : '';
}
复制代码
11,冒泡排序
// 从小到大
const sort = arr => {
let res = []
arr.forEach((v, i) => {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
[arr[i],arr[j]] = [arr[j],arr[i]]
}
}
})
return arr
}
复制代码
12,菲薄拉契数列
function Fibonacci (n) {
if ( n <= 1 ) {return 1};
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
复制代码
13,组合继承
Function Father(name){
this.name = name;
this.num = ['12'];
}
father.prototype.father = function(){
console.log(this.name);
}
function Child(age,name){
Father.call(this,name);//继承属性
this.age = age;
}
Child.prototype = new Father();//继承方法
Child.prototype.constructor = Child;
Child.prototype.sayage = function(){
console.log(this.age);
}
var c1 = new Child(16,"小花");
c1.sayage();//16
c1.sayname();//小花
c1.num.push(13);
console.log(c1.num)//12,13
var c2 = new Child(18,"小明");
c2.sayage();//18
c2.sayname();//小明
console.log(c2.num)//12
复制代码
13,时间戳获取日期时间格式
function $addZero(v, size) {
for (var i = 0, len = size - (v + '').length; i < len; i++) {
v = '0' + v;
}
return v + '';
}
function $formatDate(date, formatStr) {
var arrWeek = ['日', '一', '二', '三', '四', '五', '六'];
var str = formatStr
.replace(/yyyy|YYYY/, date.getFullYear())
.replace(/yy|YY/, $addZero(date.getFullYear() % 100, 2))
.replace(/mm|MM/, $addZero(date.getMonth() + 1, 2))
.replace(/m|M/g, date.getMonth() + 1)
.replace(/dd|DD/, $addZero(date.getDate(), 2))
.replace(/d|D/g, date.getDate())
.replace(/hh|HH/, $addZero(date.getHours(), 2))
.replace(/h|H/g, date.getHours())
.replace(/ii|II/, $addZero(date.getMinutes(), 2))
.replace(/i|I/g, date.getMinutes())
.replace(/ss|SS/, $addZero(date.getSeconds(), 2))
.replace(/s|S/g, date.getSeconds())
.replace(/w/g, date.getDay())
.replace(/W/g, arrWeek[date.getDay()]);
return str;
}
复制代码
14,获取每三位分隔符333132123 =>333,132,123
复制代码
15,获取1-100的质数
复制代码
16,判断类型
function typeIs(target) {
return Object.prototype.toString.apply(target).match(/\[object\s(\w+)\]/)[1].toLowerCase();
}
复制代码
17,把html标记转为实体编码
/**
* 把html标记转为实体编码
* @param html
* @returns {string}
*/
function $encodeHtml(html) {
if (typeof html !== 'string') {
return '';
}
var _ele = document.createElement('div');
if (document.innerText) {
_ele.innerText = html;
} else {
_ele.textContent = html;
}
return _ele.innerHTML;
}
复制代码
18, 获取服务器当前时间
function xhrMaker() {
var xhr;
try { // Firefox, Opera 8.0+, Safari
xhr = new XMLHttpRequest();
} catch (e) { // Internet Explorer
try {
xhr = new window.ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
xhr = new window.ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
xhr = null;
}
}
}
return xhr;
}
// 获取服务器当前时间
function $getServerTime(url) {
var sysTime = document.getElementById('SYSTIME');
if (sysTime) {
var ts = sysTime.value.substring(0, 19).split('-');
var dObj = new Date(ts[0], parseInt(ts[1], 10) - 1, ts[2], ts[3], ts[4], ts[5]);
return dObj;
}
var xhr = xhrMaker();
url = url || ('//' + window.location.hostname + '/favicon.ico?t=' + Math.random());
try {
xhr.open('HEAD', url, false);
xhr.send();
} catch (e) {
return new Date();
}
return new Date(xhr.getResponseHeader('Date'));
}
复制代码
- 持续更新中......
- 欢迎点赞关注
- 欢迎批评指正