個人去面試時。有時會遇到一些手寫程式碼題。
花了點時間來總結一下,希望對大家有所幫助。
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'));
}
複製程式碼
- 持續更新中......
- 歡迎點贊關注
- 歡迎批評指正