这里我总结前端面试中常见的原生JS手写实现函数,对付面试足够了,但是可能还会有露,这就得根据你自己具体的面试来总结了。其中如果有误,欢迎指正,我在这里先感谢各位!!!
Function.prototype.mycall = function () {
const args = [...arguments]
const contex = args.shift() //作用对象
let fn = Symbol()
contex[fn] = this //为作用对象添加给定的函数
let result = contex[fn](...args) //执行作用对象上的函数
delete contex[fn]
return result
}
Function.prototype.myapply = function () {
const args = [...arguments]
const contex = args.shift()
let fn = Symbol()
contex[fn] = this
let result = contex[fn](...args[0]) //不同之处
delete contex[fn]
return result
}
Function.prototype.mybind = function () {
const args = [...arguments]
const thisArg = args.shift()
const self = this
return function () {
return self.apply(thisArg, args)
}
}
function myNew() {
const args = [...arguments]
const father = args.shift()
let obj = new Object({}) //创建一个新的空对象
obj.__proto__ = father.prototype //解决原型
let result = father.call(obj, ...args) //构造函数于新对象环境中执行
// let result = father.apply(obj, [...args])
return result ? result : obj
}
function instance_of(L, R) {
// 1.如果是基本数据类型,除了null
const baseType = ['string', 'number', 'boolean', 'undefined', 'symblo', 'BigInt']
if (baseType.includes(typeof (L))) return false
// 2.如果时引用类型
let LP = L.__proto__
let RP = R.prototype
while (true) {
if (LP == null) { //找到最后一个了,__proto__为null(Object.prptptype.__prpto__ = null)
return false
}
if (LP === RP) {
return true
}
LP = LP.__proto__ //该层未找到,继续往上找
}
}
/原型链继承
function Sup (name) {
this.name = name
}
Sup.prototype.sayName = function () {
console.log(this.name)
}
function sub(name, age) {
this.name = name
this.age = age
}
sub.prototype = new Sup()//要点:继承原型链
sub.prototype.satAge = function () {
console.log(this.age)
}
//sub.prototype = new sup()
sub.prototype.sayAge = function () {
console.log(this.age)
}
//盗用构造函数继承或经典继承或对象伪装
function Sup (name) {
this.name = name
}
Sup.prototype.sayName = function () {
console.log(this.name)
}
function Sub (name, age) {
Sup.call(this, name)//要点:在子类中执行父类的构造函数并继承其构造函数中的方法,而且向父类传递参数name
this.age = age
}
//组合继承或伪经典继承
function SuperType(name) {
this.name = name
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, age) {
SuperType.call(this, name) //要点1
// SuperType.apply(this, name) //报错,apply第二个参数是Array的实例,或者arguments对象。
this.age = age
}
SubType.prototype = new SupType()//要点2
SubType.prototype.sayAge = function () {
console.log(this.age)
}
var instance = new SubType("Alo", 18)
//原型式继承
function object (o) {
function F() {}
f.prototype = o
return new F()
}
//寄生式继承
function createAnother (obj) {
let clone = object(o)
clone.sayHi = function () {
console.log('hi')
}
return clone
}
//寄生式组合继承
function createother (Sub, Sup) {
let prototype = object(Sub, Sup)
prototype.construct = sub
sub.prototype = prototype
}
function SuperType(name) {
this.name = name
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, age) {
SuperType.call(this, name) //要点1
// SuperType.apply(this, name) //报错,apply第二个参数是Array的实例,或者arguments对象。
this.age = age
}
createother(SubType, SupType)//要点2,这里于组合继承不一样
SubType.prototype.sayAge = function () {
console.log(this.age)
}
function deepClone (obj) {
let objclone = Array.isArray(obj) ? [] : {}//最后复制的对象或数组
if (obj && typeof obj === 'object') {
for (let key of obj) {//遍历obj
if (obj.hasOwnProperty(key)) {//确保是对象自身的属性而非原型链继承的
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
} else if (obj instanceof Array) {
return obj.map(item => deepClone(item))
} else (obj instanceof Function) {
return obj
return objclone
}
//另一种实现方法
function deepClone(obj) {
let cloneObj = JSON.stringify(obj)
cloneObj = JSON.parse(cloneObj)
return cloneObj
}
function isObject(obj) {
return typeof obj === 'object' && obj != null
}
function deepCompare(obj1, obj2) {
// 1.有一个或两个都不是对象
if (!isObject(obj1) || !isObject(obj2)) {
return obj1 === obj2
}
// 2.同一个对象
if (obj1 === obj2) {
return true
}
// 3.不是同一个对象
const obj1Keys = Object.keys(obj1)
const obj2Keys = Object.keys(obj2)
// 3.1键数量不一样
if (obj1Keys.length != obj2Keys.length) {
return false
}
// 3.2键数量一样
for (let key in obj1) {
const res = deepCompare(obj1[key], obj2[key])
if (!res) {
return false
}
}
return true
}
function debounce(fn, delay = 500) {
let timeout = null
return function () {
let contex = this
if (timeout) {
clearInterval(timeout)
}
timeout = setTimeout(function () {
fn.apply(contex)
}, delay)
}
}
两种方式
function throttle(fn, wait = 500) {//定时器实现
let timer = null
return function () {
const context = this
const arg = arguments
if (!timer) { //即timer不为null的时候一直没操作
timer = setTimeout(() => {
timer = null
fn.apply(context, arg)
}, wait)
}
}
}
function throttle1(fn, wait = 500) {//时间戳实现
let previous = 0
return function () {
const contex = this
const arg = arguments
let now = Date.now()
if (now - previous > wait) {
fn.apply(contex, arg)
previous = now
}
}
}
Promise.all = function (promises) {
const values = new Array(promises.length) //保存成功的结果
let resolvedCount = 0; // 保存成功promise的数量
return new Promise((resolve, reject) => {
// 遍历promises获取每个promise的结果
promises.forEach((p, index) => {
// p.then(value => { //需要防止p不是promise
Promise.resolve(p).then(value => {
resolvedCount++
values[index] = value
// 如果全部成功了,返回一个promise
if (resolvedCount === promises.length) {
resolve(values) //只发生一次
}
}, reason => {
reject(reason) //只发生一次
})
})
})
}
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
// 遍历promise获取每个promise的结果
// 遍历promises获取每个promise的结果
promises.forEach((p, index) => {
// p.then(value => { //需要防止p不是promise
Promise.resolve(p).then(value => {
resolve(value) //只发生一次,谁先成功就返回该成功值
}, reason => {
reject(reason) //只发生一次 谁先失败就返回失败值
})
})
})
}
function add() {
let res = [...arguments].reduce((a, b) => a + b)
let temp = function () {
if (arguments.length) {
res += [...arguments].reduce((a, b) => a + b) // 累加
return temp
} else {
return res
}
}
temp.toString = function () { // 重写toSting() 方法
return res;
}
return temp
}
var num = 0
var max = 10
function incrementNumber() {
num++
// 如果执行次数未达到max设定的值,则设置另一次超时调用
if (num < max) {
console.log(num)
setTimeout(incrementNumber, 1000)
} else {
alert('done')
}
}
setTimeout(incrementNumber, 1000)
var Ajax = {
get: function(url, fn) {
//XMLHttpRequest对象用于在后台与服务器交换数据
var xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.onreadystatechange = function() {
//readyState == 4说明请求已完成
if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) {
//从服务器获得数据
fn.call(this, xhr.resposeText)
}
}
xhr.send()
},
//data应为'a=a1&b=b1'这种字符串格式,在jq里,如果data为对象会自动将对象转换为这种字符串
post: function(url, data, fn) {
var xhr = new XMLHttpRequest()
xhr.open("POST", url, true)
//添加http头,发送信息至服务器时内容编码类型
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) {
//从服务器获得数据
fn.call(this, xhr.resposeText)
}
}
xhr.send(data)
}
}
window.onscroll = function() {
//文档内容实际高度(包括超出视窗的溢出部分)
var scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight)
//滚动条的滚动距离
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
//窗口可视范围高度
var clientHeight = window.innerHeight || Math.min(document.documentElement.clientHeight, document.body.clientHeight)
if(clientHeight + scrollTop >= scrollHeight){
console.log("===加载更多内容……===");
}
}
//发布订阅中心,on-订阅,off取消,emit发布,内部需要一个单独事件中心caches进行存储
interface CacheProps {//单独的事件中心
[key: string]: Array <((data ? : unknow) => void)>
}
class Observe {
private caches: CacheProps = {}//事件中心
on (eventName: string, fn: (data ? : unknow) => void) {// eventName事件名-独一无二, fn订阅后执行的自定义行为
this.caches[eventName] = this.caches[eventName] || []
this.caches[eventName].push(fn)
}
emit (eventName: string, data ? : unknow) {// 发布 => 将订阅的事件进行统一执行
if (this.caches[eventName]) {
this.caches[eventName].forEach((fn: (data ? : unknow) => void) => fn(data))
}
}
off (eventName: string, fn: (data ? : unknow) => void) {
if (this.caches[eventName]) {
const newCaches = fn ? this.caches[eventName].filter(e => e !== fn) : []
this.caches[eventName] = newCaches
}
}
}
function arratTotree (arr) {
let tem = {}//创建临时对象
let tree = {}//转换后的树
//先遍历数组,将数组中每一项推入tem中
for (let i of arr) {
tem[arr[i][id]] = arr[i]
}
//遍历tem,将当前字节点与父节点建立连接
for (let i of tem) {
if (Array.isArray(i)) {
arr2Tree(i)
} else if (tem[i][parentid] !== 'root') {//父节点不是根节点
if (!tem[tem[i][parentid]].children) {//若父节点的孩子节点为空
tem[tem[i][parentid]].children = new Array()//直接为其创建一个孩子节点数组
}
tem[tem[i][parentid]].children.push(tem[i])//并且将当前节点推入父节点的孩子节点数组中
} else {
tree[tem[i][id]] = tem[i]
}
}
}
return tree
//方法1
function sleep (time) {
return new Promise(resolve => setTimeout(time))
}
const t1 = +new Date()
sleep(300).then(() => {
const t2 = +new Date()
console.log(t2 - t1)
})
//方法2
async function test() {
for (var i = 0; i < 10; i++) {
await sleep(1000);
console.log(i);
}
}
function sleep(delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(1)
} catch (e) {
reject(0)
}
}, delay);
})
}
test()
Array.prototype.myMap = function (fn, context) {
let arr = this
let res = []
for (let i = 0; i < arr.length; i ++) {
res.push(fn.call(context, arr[i], i, arr))
}
return res
}
Array.prototype.myReduce = function (fn, base) {
let initarr = this
let arr = initarr.concat()
if (base) arr.unshift(base)
let index, newValue
while (arr.length > 1) {
index = initarr.length - arr.length + 1
newValue = fn.call(null, arr[0], arr[1], index, initarr)
arr.splice(0, 2, newValue)
}
return newValue
}
Array.prototype.myfilter = function (fn, context) {
let arr = this
let tem = []
for (let i = 0; i < arr.length; i ++) {
let res = fn.call(context, arr[i], i, arr)
if (res) tem.push(arr[i])
}
return tem
}
Array.prototype.myforEach = function (fn, context) {
let arr = this
for (let i = 0; i < arr.length; i ++) {
fn.call(context, arr[i], i, arr)
}
}
Array.prototype.myfind = function (fn, context) {
let arr = this
for (let i = 0; i < arr.length; i ++) {
let res = fn.call(context, arr[i], i, arr)
if (res) return arr[i]
}
return undefined
}
Array.prototype.mysome = function (fn, context) {
let arr = this
for (let i = 0; i < arr.length; i ++) {
let res = fn.call(context, arr[i], i, arr)
if (res) return true
}
return false
}
Array.prototype.myevery = function (fn, context) {
let arr = this
for (let i = 0; i < arr.length; i ++) {
let res = fn.call(context, arr[i], i, arr)
if (!res) return false
}
return true
}
Array.prototype.myincludes = function (val, index) {
let arr = this
let k = Math.max(index >= 0 ? index : arr.length - Math.abs(index), 0)
for (; k < arr.length; k ++) {
if (arr[k] === val) {
return true
}
}
return false
}
Array.prototype.myjoin = function (connector) {
let arr = this
let str = ''
for (let i = 0; i < arr.length; i ++) {
if (i == arr.length - 1) str += arr[i]
else {
str += arr[i] + connector.toString()
}
}
return str
}
Array.prototype.mapbyreduce = function (fn, context) {
let arr = this
return arr.reduce((pre, cur, index, arr) => {
let res = fn.call(context, cur, index, arr)
return [...pre, res]
}, [])
}
Array.prototype.myconcat = function () {
let res = JSON.parse(JSON.stringify(this))
for (let i = 0; i < arguments.length; i ++) {
let arg = arguments[i]
for (let j = 0; j < arg.length; j ++) {
res.push(arg[j])
}
}
return res
}
function quick (arr) {
if (arr.length <= 1) return arr
let pivotindex = Math.floor(arr.length / 2)
let pivot = arr.splice(pivotindex, 1)
let left = []
let right = []
for (let i = 0; i < arr.length; i ++) {
if (arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quick(left).concat(pivot, quick(right))
}
Array.prototype.myflat = function (count) {
let arr = this
if (count == 0) return arr
return arr.reduce((res, value)=> {
if (Array.isArray(value)) {
res = res.concat(myflat(count - 1))
} else {
res = res.concat(value)
}
return res
}, [])
}
Array.prototype.mysplice = function () {
let arr = this
let index = arguments[0]//第一个参数
let num = arguments[1]//第二个参数
let len = arguments.length
let content = []
if (len == 2) {//仅有两个参数,则splice函数用于删除元素
return arr.slice(0, index).concat(arr.slice(index + num, arr.length))
} else if (len > 2) {
for (let i = 2; i < len; i ++) {//将其余参数放入数组content中
content.push(arguments[i])
}
if (num == 0) {//有2个以上的参数,且第二个参数为0时,则splice函数为插入元素
return arr.slice(0, index).concat(content, arr.slice(index, arr.length))
} else if (num > 0) {//有2个以上的参数,且第二个参数不为0时,则splice函数为替换元素
return arr.slice(0, index).concat(content, arr.slice(index + num, arr.length))
}
} else {
return arr
}
}
Array.prototype.isArray = function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
Array.prototype.myslice = function (start, end) {
let arr = this
start = start === undefined ? 0 : start
end = end === undefined ? arr.kength : end
let res = []
for (let i = start; i < end; i ++) {
res.push(arr[i])
}
return res
}
function render(vnode, container) {
return container.appendChild(_render(vnode))
}
function _render (vnode) {
if (typeof vnode === 'number') {
vnode = String(vnode)
}
if (typeof vnode === 'string') {
return document.createTextNode(vnode)
}
let dom = document.createElement(vnode.tag)
if (vnode.attrs) {
Object.keys(vnode.attrs).forEach(key => {
let value = vnode.attrs[key]
dom.setAttribute(key, value)
})
}
vnode.children.forEach(child => _render(child))
return dom
}
function reder(vnode, con) {
return con.appendChild(_render(vnode))
}
function parse (str, obj) {
let res = ''
let flag = false
let start
for (let i = 0; i < str.length; i ++) {
if (str[i] === '{') {
flag = true
start = i + 1
continue
}
if (!flag) {
res += str[i]
} else {
if (str[i] === '}') {
flag = false
res += match(str.slice(start, i), obj)
}
}
}
}
function match (str, obj) {
let keys = obj.split(".").slice(1)
let index
let o = obj
while (index < keys.length) {
let key = keys[index]
if (!o[key]) {
return `{${str}}`
} else {
o = o[key]
}
}
return o
}