共计 19551 个字符,预计需要花费 49 分钟才能阅读完成。
前言
大家好,我是林三心,根底是进阶的前提 ,后面我给大家分享了本菜鸟这一年来笔记中的50 个 JS 根底知识点 和50 个 JS 高级知识点
- 工作中遇到的 50 个 JavaScript 的根底知识点,满分找我拿奖品!【浏览:7.8k,点赞:285】
- 万字总结」熬夜总结 50 个 JS 的高级知识点,全都会你就是神!!!【浏览:1.5w,点赞:812】
明天就给大家分享一下我笔记中的56 个 JavaScript 手写知识点
注明:此文章不含 算法题
面试常考
1、实现原生的 AJAX 申请
const ajax = {get(url, fn) {const xhr = new XMLHttpRequest() | |
xhr.open('GET', url, true)// 第三个参数异步与否 | |
xhr.onreadystatechange = function() {if (xhr.readyState === 4) {fn(xhr.responeText) | |
} | |
} | |
xhr.send()}, | |
post(url, data, fn) {const xhr = new XMLHttpRequest() | |
xhr.open('POST', url, true) | |
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded') | |
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {fn(xhr.responeText) | |
} | |
} | |
xhr.send(data) | |
} | |
} |
2、手写 new 的过程
function myNew(fn, ...args) {const obj = {} | |
obj.__proto__ = fn.prototype | |
fn.apply(obj, args) | |
return obj | |
} |
3、instanceof 关键字
function instanceOf(father, child) { | |
const fp = father.prototype | |
var cp = child.__proto__ | |
while (cp) {if (cp === fp) {return true} | |
cp = cp.__proto__ | |
} | |
return false | |
} |
4、实现防抖函数
function debounce(fn, delay = 500) { | |
let timer; | |
return function () {if (timer) {clearTimeout(timer) | |
} | |
const args = arguments | |
timer = setTimeout(() => {fn.apply(this, args) // 扭转 this 指向为调用 debounce 所指的对象 | |
}, delay) | |
} | |
} |
5、实现节流函数
function throttle(fn, delay = 200) { | |
let flag = true | |
return function () {if (!flag) return | |
flag = false | |
const args = arguments | |
setTimeout(() => {fn.apply(this, args) | |
flag = true | |
}, delay) | |
} | |
} |
6、实现数组去重
题目形容:实现一个数组的去重
// 第一种:Map 记录 | |
function quchong1(arr) {const newArr = [] | |
arr.reduce((pre, next) => {if (!pre[next]) {pre[next] = 1 | |
newArr.push(next) | |
} | |
return pre | |
}, {}) | |
return newArr | |
} | |
// 第二种:Set 去重 | |
function quchong2(arr) {return [...new Set(arr)] | |
} |
7、用 setTimeout 实现 setInterval
题目形容:setinterval 用来实现循环定时调用 可能会存在肯定的问题 能用 settimeout 解决吗
function mySetTimout(fn, delay) { | |
let timer = null | |
const interval = () => {fn() | |
timer = setTimeout(interval, delay) | |
} | |
setTimeout(interval, delay) | |
return {cancel: () => {clearTimeout(timer) | |
} | |
} | |
} | |
// 测试 | |
const {cancel} = mySetTimout(() => console.log(888), 1000) | |
setTimeout(() => {cancel() | |
}, 4000) |
8、用 setInterval 实现 setTimeout
题目阐明:没有,就是想刁难你
function mySetInterval(fn, delay) {const timer = setInterval(() => {fn() | |
clearInterval(timer) | |
}, delay) | |
} | |
// 测试 | |
mySetInterval(() => console.log(888), 1000) |
9、实现一个 compose 函数
题目阐明:实现以下成果
function fn1(x) {return x + 1;} | |
function fn2(x) {return x + 2;} | |
function fn3(x) {return x + 3;} | |
function fn4(x) {return x + 4;} | |
const a = compose(fn1, fn2, fn3, fn4); | |
console.log(a) | |
console.log(a(1)); // 1+2+3+4=11 |
实现如下:
function compose(...fn) {if (fn.length === 0) return (num) => num | |
if (fn.length === 1) return fn[0] | |
return fn.reduce((pre, next) => {return (num) => {return next(pre(num)) | |
} | |
}) | |
} |
10、实现一个科里化函数
题目要求:
const add = (a, b, c) => a + b + c; | |
const a = currying(add, 1); | |
console.log(a(2,3)) // 1 + 2 + 3=6 |
实现如下:
function currying(fn, ...args1) { | |
// 获取 fn 参数有几个 | |
const length = fn.length | |
let allArgs = [...args1] | |
const res = (...arg2) => {allArgs = [...allArgs, ...arg2] | |
// 长度相等就返回执行后果 | |
if (allArgs.length === length) {return fn(...allArgs) | |
} else { | |
// 不相等持续返回函数 | |
return res | |
} | |
} | |
return res | |
} | |
// 测试:const add = (a, b, c) => a + b + c; | |
const a = currying(add, 1); | |
console.log(a(2,3)) |
11、实现一个 LRU 缓存函数
题目阐明:
实现如下:
class LRUCache {constructor(size) { | |
this.size = size | |
this.cache = new Map()} | |
get(key) {const hasKey = this.cache.has(key) | |
if (hasKey) {const val = this.cache.get(key) | |
this.cache.delete(key) | |
this.cache.set(key, val) | |
return val | |
} else {return -1} | |
} | |
put(key, val) {const hasKey = this.cache.has(key) | |
if (hasKey) {this.cache.delete(key) | |
} | |
this.cache.set(key, val) | |
if (this.cache.size > this.size) {this.cache.delete(this.cache.keys().next().value) | |
} | |
} | |
} |
12、简略实现 公布订阅模式
题目形容: 实现一个公布订阅模式领有
on emit once off
办法
class EventEmitter {constructor() {this.cache = {} | |
} | |
on(name, fn) {const tasks = this.cache[name] | |
if (tasks) {this.cache[name].push(fn) | |
} else {this.cache[name] = [fn] | |
} | |
} | |
off(name, fn) {const tasks = this.cache[name] | |
if (task) {const index = tasks.findIndex(item => item === fn) | |
if (index >= 0) {this.cache[name].splice(index, 1) | |
} | |
} | |
} | |
emit(name, once = false, ...args) { | |
// 复制一份。避免回调里持续 on,导致死循环 | |
const tasks = this.cache[name].slice() | |
if (tasks) {for (let fn of tasks) {fn(...args) | |
} | |
} | |
if (once) {delete this.cache[name] | |
} | |
} | |
once(name, ...args) {this.emit(name, true, ...args) | |
} | |
} |
13、实现 JSON.parse
题目形容:实现
JSON.parse
function parse (json) {return eval("(" + json + ")"); | |
} |
14、将 DOM 转化成树结构对象
题目形容:
<div> | |
<span></span> | |
<ul> | |
<li></li> | |
<li></li> | |
</ul> | |
</div> | |
将上方的 DOM 转化为上面的树结构对象 | |
{ | |
tag: 'DIV', | |
children: [{ tag: 'SPAN', children: [] }, | |
{ | |
tag: 'UL', | |
children: [{ tag: 'LI', children: [] }, | |
{tag: 'LI', children: [] } | |
] | |
} | |
] | |
} |
实现如下:
function dom2tree(dom) {const obj = {} | |
obj.tag = dom.tagName | |
obj.children = [] | |
dom.childNodes.forEach(child => obj.children.push(dom2tree(child))) | |
return obj | |
} |
15、将树结构转换为 DOM
题目形容:
{ | |
tag: 'DIV', | |
children: [{ tag: 'SPAN', children: [] }, | |
{ | |
tag: 'UL', | |
children: [{ tag: 'LI', children: [] }, | |
{tag: 'LI', children: [] } | |
] | |
} | |
] | |
} | |
将上方的树结构对象转化为上面的 DOM | |
<div> | |
<span></span> | |
<ul> | |
<li></li> | |
<li></li> | |
</ul> | |
</div> |
实现如下:
// 真正的渲染函数 | |
function _render(vnode) { | |
// 如果是数字类型转化为字符串 | |
if (typeof vnode === "number") {vnode = String(vnode); | |
} | |
// 字符串类型间接就是文本节点 | |
if (typeof vnode === "string") {return document.createTextNode(vnode); | |
} | |
// 一般 DOM | |
const dom = document.createElement(vnode.tag); | |
if (vnode.attrs) { | |
// 遍历属性 | |
Object.keys(vnode.attrs).forEach((key) => {const value = vnode.attrs[key]; | |
dom.setAttribute(key, value); | |
}); | |
} | |
// 子数组进行递归操作 | |
vnode.children.forEach((child) => dom.appendChild(_render(child))); | |
return dom; | |
} |
16、判断一个对象有环援用
题目形容:验证一个对象有无环援用
var obj = { | |
a: { | |
c: [1, 2] | |
}, | |
b: 1 | |
} | |
obj.a.c.d = obj | |
console.log(cycleDetector(obj)) // true |
实现思路:用一个数组存储每一个遍历过的对象,下次找到数组中存在,则阐明环援用
function cycleDetector(obj) {const arr = [obj] | |
let flag = false | |
function cycle(o) {const keys = Object.keys(o) | |
for (const key of keys) {const temp = o[key] | |
if (typeof temp === 'object' && temp !== null) {if (arr.indexOf(temp) >= 0) { | |
flag = true | |
return | |
} | |
arr.push(temp) | |
cycle(temp) | |
} | |
} | |
} | |
cycle(obj) | |
return flag | |
} |
17、计算一个对象的层数
题目形容:给你一个对象,统计一下它的层数
const obj = {a: { b: [1] }, | |
c: {d: { e: { f: 1} } } | |
} | |
console.log(loopGetLevel(obj)) // 4 |
实现如下:
function loopGetLevel(obj) { | |
var res = 1; | |
function computedLevel(obj, level) { | |
var level = level ? level : 0; | |
if (typeof obj === 'object') {for (var key in obj) {if (typeof obj[key] === 'object') {computedLevel(obj[key], level + 1); | |
} else {res = level + 1 > res ? level + 1 : res;} | |
} | |
} else {res = level > res ? level : res;} | |
} | |
computedLevel(obj) | |
return res | |
} |
18、对象的扁平化
题目形容:
const obj = { | |
a: { | |
b: 1, | |
c: 2, | |
d: {e: 5} | |
}, | |
b: [1, 3, {a: 2, b: 3}], | |
c: 3 | |
} | |
flatten(obj) 后果返回如下 | |
// { | |
// 'a.b': 1, | |
// 'a.c': 2, | |
// 'a.d.e': 5, | |
// 'b[0]': 1, | |
// 'b[1]': 3, | |
// 'b[2].a': 2, | |
// 'b[2].b': 3 | |
// c: 3 | |
// } |
实现如下:
const isObject = (val) => typeof val === "object" && val !== null | |
function flatten(obj) {if (!isObject(obj)) return | |
const res = {} | |
const dfs = (cur, prefix) => {if (isObject(cur)) {if (Array.isArray(cur)) {cur.forEach((item, index) => {dfs(item, `${prefix}[${index}]`) | |
}) | |
} else {for(let key in cur) {dfs(cur[key], `${prefix}${prefix ? '.' : ''}${key}`) | |
} | |
} | |
} else {res[prefix] = cur | |
} | |
} | |
dfs(obj, '') | |
return res | |
} | |
// 测试 | |
console.log(flatten(obj)) |
19、实现 (a == 1 && a == 2 && a == 3) 为 true
题目形容:
实现 (a == 1 && a == 2 && a == 3) 为 true
// 第一种办法 | |
var a = { | |
i: 1, | |
toString: function () {return a.i++;} | |
} | |
console.log(a == 1 && a == 2 && a == 3) // true | |
// 第二种办法 | |
var a = [1, 2, 3]; | |
a.join = a.shift; | |
console.log(a == 1 && a == 2 && a == 3); // true | |
// 第三种办法 | |
var val = 0; | |
Object.defineProperty(window, 'a', {get: function () {return ++val;} | |
}); | |
console.log(a == 1 && a == 2 && a == 3) // true |
20、实现限度并发的 Promise 调度器
题目形容:JS 实现一个带并发限度的异步调度器 Scheduler,保障同时运行的工作最多有两个
addTask(1000,"1"); | |
addTask(500,"2"); | |
addTask(300,"3"); | |
addTask(400,"4"); | |
的输入程序是:2 3 1 4 | |
整个的残缺执行流程:一开始 1、2 两个工作开始执行 | |
500ms 时,2 工作执行结束,输入 2,工作 3 开始执行 | |
800ms 时,3 工作执行结束,输入 3,工作 4 开始执行 | |
1000ms 时,1 工作执行结束,输入 1,此时只剩下 4 工作在执行 | |
1200ms 时,4 工作执行结束,输入 4 |
实现如下:
class Scheduler {constructor(limit) {this.queue = [] | |
this.limit = limit | |
this.count = 0 | |
} | |
add(time, order) {const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(order) | |
resolve()}, time) | |
}) | |
} | |
this.queue.push(promiseCreator) | |
} | |
taskStart() {for(let i = 0; i < this.limit; i++) {this.request() | |
} | |
} | |
request() {if (!this.queue.length || this.count >= this.limit) return | |
this.count++ | |
this.queue.shift()().then(() => { | |
this.count-- | |
this.request()}) | |
} | |
} | |
// 测试 | |
const scheduler = new Scheduler(2); | |
const addTask = (time, order) => {scheduler.add(time, order); | |
}; | |
addTask(1000, "1"); | |
addTask(500, "2"); | |
addTask(300, "3"); | |
addTask(400, "4"); | |
scheduler.taskStart(); |
21、实现 lazyMan 函数
题目形容:
实现一个 LazyMan,能够依照以下形式调用: | |
LazyMan(“Hank”)输入: | |
Hi! This is Hank! | |
LazyMan(“Hank”).sleep(10).eat(“dinner”)输入 | |
Hi! This is Hank! | |
// 期待 10 秒.. | |
Wake up after 10 | |
Eat dinner~ | |
LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输入 | |
Hi This is Hank! | |
Eat dinner~ | |
Eat supper~ | |
LazyMan(“Hank”).eat(“supper”).sleepFirst(5)输入 | |
// 期待 5 秒 | |
Wake up after 5 | |
Hi This is Hank! | |
Eat supper |
实现如下:
class _LazyMan {constructor(name) {this.tasks = [] | |
const task = () => {console.log(`Hi! This is ${name}`) | |
this.next()} | |
this.tasks.push(task) | |
setTimeout(() => {this.next() | |
}, 0) | |
} | |
next() {const task = this.tasks.shift() | |
task && task()} | |
sleep(time) {this.sleepWrapper(time, false) | |
return this | |
} | |
sleepFirst(time) {this.sleepWrapper(time, true) | |
return this | |
} | |
sleepWrapper(time, first) {const task = () => {setTimeout(() => {console.log(`Wake up after ${time}`) | |
this.next()}, time * 1000) | |
} | |
if (first) {this.tasks.unshift(task) | |
} else {this.tasks.push(task) | |
} | |
} | |
eat(food) {const task = () => {console.log(`Eat ${food}`); | |
this.next();}; | |
this.tasks.push(task); | |
return this; | |
} | |
} | |
// 测试 | |
const lazyMan = (name) => new _LazyMan(name) | |
lazyMan('Hank').sleep(1).eat('dinner') | |
lazyMan('Hank').eat('dinner').eat('supper') | |
lazyMan('Hank').eat('supper').sleepFirst(5) |
22、实现 add 函数
题目形容:实现一个 add 办法 使计算结果可能满足如下预期:
- add(1)(2)(3)()=6
- add(1,2,3)(4)()=10
function add(...args1) {let allArgs = [...args1] | |
function fn(...args2) {if (!args2.length) return fn.toString() | |
allArgs = [...allArgs, ...args2] | |
return fn | |
} | |
fn.toString = function () {return allArgs.reduce((pre, next) => pre + next) | |
} | |
return fn | |
} | |
// 测试 | |
console.log(add(1)(2)(3)()) | |
console.log(add(1, 2)(3)()) |
23、实现一个合格的深拷贝
举荐看我这篇:深拷贝有这 5 个段位,你只是青铜段位?还想涨薪?
24、实现 Promise
举荐看我这篇:看了就会,手写 Promise 原理,最通俗易懂的版本!!!【浏览:1.3w,点赞:460】
25、实现 async/await
举荐看我这篇:7 张图,20 分钟就能搞定的 async/await 原理!为什么要拖那么久?【浏览:2.15w,点赞:460】
Array 篇
定义一个测试数组
const players = [{ name: '科比', num: 24}, | |
{name: '詹姆斯', num: 23}, | |
{name: '保罗', num: 3}, | |
{name: '威少', num: 0}, | |
{name: '杜兰特', num: 35} | |
] |
26、forEach
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_forEach = function (callback) {for (let i = 0; i < this.length; i++) {callback(this[i], i, this) } } players.sx_forEach((item, index, arr) => {console.log(item, index) }) // {name: '科比', num: 24} 0 // {name: '詹姆斯', num: 23} 1 // {name: '保罗', num: 3} 2 // {name: '威少', num: 0} 3 // {name: '杜兰特', num: 35} 4 27、map
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_map = function (callback) {const res = [] for (let i = 0; i < this.length; i++) {res.push(callback(this[i], i, this)) } return res } console.log(players.sx_map((item, index) => `${item.name}--${item.num}--${index}`)) // ['科比 --24--0', '詹姆斯 --23--1', '保罗 --3--2', '威少 --0--3', '杜兰特 --35--4'] 28、filter
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_filter = function (callback) {const res = [] for (let i = 0; i < this.length; i++) {callback(this[i], i, this) && res.push(this[i]) } return res } console.log(players.sx_filter(item => item.num >= 23)) // [// { name: '科比', num: 24}, // {name: '詹姆斯', num: 23}, // {name: '杜兰特', num: 35} // ] 29、every
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_every = function (callback) { let flag = true for (let i = 0; i < this.length; i++) {flag = callback(this[i], i, this) if (!flag) break } return flag } console.log(players.sx_every(item => item.num >= 23)) // false console.log(players.sx_every(item => item.num >= 0)) // true 30、some
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_some = function (callback) { let flag = false for (let i = 0; i < this.length; i++) {flag = callback(this[i], i, this) if (flag) break } return flag } console.log(players.sx_some(item => item.num >= 23)) // true console.log(players.sx_some(item => item.num >= 50)) // false
31、reduce
参数代表含意
- pre:前一项
- next:下一项
- index:以后索引
-
arr:数组自身
Array.prototype.sx_reduce = function (callback, initValue) { let start = 0, pre if (initValue) {pre = initValue} else {pre = this[0] start = 1 } for (let i = start; i < this.length; i++) {pre = callback(pre, this[i], i, this) } return pre } // 计算所有 num 相加 const sum = players.sx_reduce((pre, next) => {return pre + next.num}, 0) console.log(sum) // 85
32、findIndex
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_findIndex = function (callback) {for (let i = 0; i < this.length; i++) {if (callback(this[i], i, this)) {return i} } return -1 } console.log(players.sx_findIndex(item => item.name === '科比')) // 0 console.log(players.sx_findIndex(item => item.name === '安东尼')) // -1
33、find
参数代表含意
- item:遍历项
- index:遍历项的索引
-
arr:数组自身
Array.prototype.sx_find = function (callback) {for (let i = 0; i < this.length; i++) {if (callback(this[i], i, this)) {return this[i] } } return undefined } console.log(players.sx_find(item => item.name === '科比')) // {name: '科比', num: 24} console.log(players.sx_find(item => item.name === '安东尼')) // undefined
34、fill
用途:填充数组
参数代表含意
- initValue:填充的值
- start:开始填充索引,默认 0
- end:完结填充索引,默认 length
Array.prototype.sx_fill = function (value, start = 0, end) { | |
end = end || this.length | |
for (let i = start; i < end; i++) {this[i] = value | |
} | |
return this | |
} | |
console.log(players.sx_fill('林三心', 1, 3)) | |
// [// { name: '科比', num: 24}, | |
// '林三心', | |
// '林三心', | |
// '林三心', | |
// {name: '杜兰特', num: 35} | |
// ] |
35、includes
用途:查找元素,查到返回true
,反之返回false
,可查找NaN
Array.prototype.sx_includes = function (value, start = 0) {if (start < 0) start = this.length + start | |
const isNaN = Number.isNaN(value) | |
for (let i = start; i < this.length; i++) {if (this[i] === value || Number.isNaN(this[i]) === isNaN) {return true} | |
} | |
return false | |
} | |
console.log([1, 2, 3].sx_includes(2)) // true | |
console.log([1, 2, 3, NaN].sx_includes(NaN)) // true | |
console.log([1, 2, 3].sx_includes(1, 1)) // false |
36、join
用途:将数组用分隔符拼成字符串,分隔符默认为,
Array.prototype.sx_join = function (s = ',') { | |
let str = '' | |
for(let i = 0; i < this.length; i++) {str = i === 0 ? `${str}${this[i]}` : `${str}${s}${this[i]}` | |
} | |
return str | |
} | |
console.log([1, 2, 3].sx_join()) // 1,2,3 | |
console.log([1, 2, 3].sx_join('*')) // 1*2*3 |
37、flat
Array.prototype.sx_flat = function () { | |
let arr = this | |
while (arr.some(item => Array.isArray(item))) {arr = [].concat(...arr) | |
} | |
return arr | |
} | |
const testArr = [1, [2, 3, [4, 5]], [8, 9]] | |
console.log(testArr.sx_flat()) | |
// [1, 2, 3, 4, 5, 8, 9] |
38、splice
难点
-
截取长度和替换长度的比拟,不同状况
Array.prototype.sx_splice = function (start, length, ...values) { length = start + length > this.length - 1 ? this.length - start : length const res = [], tempArr = [...this] for (let i = start; i < start + values.length; i++) {this[i] = values[i - start] } if (values.length < length) { const cha = length - values.length for (let i = start + values.length; i < tempArr.length; i++) {this[i] = tempArr[i + cha] } this.length = this.length - cha } if (values.length > length) {for (let i = start + length; i < tempArr.length; i++) {this.push(tempArr[i]) } } for (let i = start; i < start + length; i++) {res.push(tempArr[i]) } return res }
Object 篇
定义一个测试对象
const obj = { | |
name: '林三心', | |
age: 22, | |
gender: '男' | |
} |
39、entries
用途:将对象转成键值对数组
Object.prototype.sx_entries = function (obj) {const res = [] | |
for (let key in obj) {obj.hasOwnProperty(key) && res.push([key, obj[key]]) | |
} | |
return res | |
} | |
console.log(Object.sx_entries(obj)) | |
// [[ 'name', '林三心'], ['age', 22], ['gender', '男'] ] |
40、fromEntries
用途:跟 entries
相同,将键值对数组转成对象
Object.prototype.sx_fromEntries = function (arr) {const obj = {} | |
for (let i = 0; i < arr.length; i++) {const [key, value] = arr[i] | |
obj[key] = value | |
} | |
return obj | |
} | |
console.log(Object.sx_fromEntries([['name', '林三心'], ['age', 22], ['gender', '男']])) | |
// {name: '林三心', age: 22, gender: '男'} |
41、keys
用途:将对象的 key 转成一个数组合集
Object.prototype.sx_keys = function (obj) {const keys = [] | |
for (let key in obj) {obj.hasOwnProperty(key) && res.push(key) | |
} | |
return keys | |
} | |
console.log(Object.keys(obj)) | |
// ['name', 'age', 'gender'] |
42、values
用途:将对象的所有值转成数组合集
Object.prototype.sx_values = function (obj) {const values = [] | |
for (let key in obj) {obj.hasOwnProperty(key) && values.push(obj[key]) | |
} | |
return values | |
} | |
console.log(Object.sx_values(obj)) | |
// ['林三心', 22, '男'] |
43、instanceOf
用途:A instanceOf B,判断 A 是否通过 B 的原型链
function instanceOf(father, child) { | |
const fp = father.prototype | |
var cp = child.__proto__ | |
while (cp) {if (cp === fp) {return true} | |
cp = cp.__proto__ | |
} | |
return false | |
} | |
function Person(name) {this.name = name} | |
const sx = new Person('林三心') | |
console.log(instanceOf(Person, sx)) // true | |
console.log(instanceOf(Person, sx2)) // false |
44、is
用途:Object.is(a, b),判断 a 是否等于 b
Object.prototype.sx_is = function (x, y) {if (x === y) { | |
// 避免 -0 和 +0 | |
return x !== 0 || 1 / x === 1 / y | |
} | |
// 避免 NaN | |
return x !== x && y !== y | |
} | |
const a = {name: '林三心'} | |
const b = a | |
const c = {name: '林三心'} | |
console.log(Object.sx_is(a, b)) // true | |
console.log(Object.sx_is(a, c)) // false |
45、Object.assign
难点
- assign 接管多个对象,并将多个对象合成一个对象
- 这些对象如果有重名属性,当前来的对象属性值为准
-
assign 返回一个对象,
这个对象 === 第一个对象
Object.prototype.sx_assign = function (target, ...args) {if (target === null || target === undefined) {throw new TypeError('Cannot convert undefined or null to object') } target = Object(target) for (let nextObj of args) {for (let key in nextObj) {nextObj.hasOwnProperty(key) && (target[key] = nextObj[key]) } } return target } const testa = {name: '林三心'} const testb = {name: 'sunshine_lin', age: 22} const testc = {age: 18, gender: '男'} const testd = Object.sx_assign(testa, testb, testc) console.log(testd) // {name: 'sunshine_lin', age: 18, gender: '男'} console.log(testa === testd) // true
Function 篇
46、call
Function.prototype.sx_call = function (obj, ...args) { | |
obj = obj || window | |
// Symbol 是惟一的,避免重名 key | |
const fn = Symbol() | |
obj[fn] = this | |
// 执行,返回执行值 | |
return obj[fn](...args) | |
} | |
const testobj = { | |
name: '林三心', | |
testFn(age) {console.log(`${this.name}${age}岁了 `) | |
} | |
} | |
const testobj2 = {name: 'sunshine_lin'} | |
testobj.testFn.sx_call(testobj2, 22) // sunshine_lin22 岁了 |
47、apply
Function.prototype.sx_apply = function (obj, args) { | |
obj = obj || window | |
// Symbol 是惟一的,避免重名 key | |
const fn = Symbol() | |
obj[fn] = this | |
// 执行,返回执行值 | |
return obj[fn](...args) | |
} | |
const testobj = { | |
name: '林三心', | |
testFn(age) {console.log(`${this.name}${age}岁了 `) | |
} | |
} | |
const testobj2 = {name: 'sunshine_lin'} | |
testobj.testFn.sx_apply(testobj2, [22]) // sunshine_lin22 岁了 |
48、Function.prototype.bind
难点:
- bind 是返回一个函数,而不是执行后果
-
bind 返回的函数,拿来当做构造函数,该怎么解决
Function.prototype.sx_bind = function (obj, ...args) { obj = obj || window // Symbol 是惟一的,避免重名 key const fn = Symbol() obj[fn] = this const _this = this const res = function (...innerArgs) {console.log(this, _this) if (this instanceof _this) {this[fn] = _this this[fn](...[...args, ...innerArgs]) delete this[fn] } else {obj[fn](...[...args, ...innerArgs]) delete obj[fn] } } res.prototype = Object.create(this.prototype) return res }
String 篇
49、slice
参数代表含意
- start:开始截取的字符索引(蕴含此字符)
- end:完结截取的字符索引 (不蕴含此字符)
留神点 - start > end:返回空字符串
- start < 0:
start = 数组长度 + start
String.prototype.sx_slice = function (start = 0, end) { | |
start = start < 0 ? this.length + start : start | |
end = !end && end !== 0 ? this.length : end | |
if (start >= end) return ''let str ='' | |
for (let i = start; i < end; i++) {str += this[i] | |
} | |
return str | |
} | |
console.log(str.sx_slice(2)) // nshine_lin | |
console.log(str.sx_slice(-2)) // in | |
console.log(str.sx_slice(-9, 10)) // shine_l | |
console.log(str.sx_slice(5, 1)) // '' |
50、substr
参数代表含意
- start:开始截取的字符索引(蕴含此字符)
- length:截取的长度
留神点 - start < 0:
start = 数组长度 + start
- length 超出所能截取范畴,须要做解决
- length < 0:返回空字符串
String.prototype.sx_substr = function (start = 0, length) {if (length < 0) return '' | |
start = start < 0 ? this.length + start : start | |
length = (!length && length !== 0) || length > this.length - start ? this.length : start + length | |
let str = '' | |
for (let i = start; i < length; i++) {str += this[i] | |
} | |
return str | |
} | |
console.log(str.sx_substr(3)) // shine_lin | |
console.log(str.sx_substr(3, 3)) // shi | |
console.log(str.sx_substr(5, 300)) // ine_lin |
51、substring
性能与 slice
大致相同
区别之处
-
start > end:调换值
String.prototype.sx_sunstring = function (start = 0, end) { start = start < 0 ? this.length + start : start end = !end && end !== 0 ? this.length : end if (start >= end) [start, end] = [end, start] let str = '' for (let i = start; i < end; i++) {str += this[i] } return str } console.log(str.sx_sunstring(2)) // nshine_lin console.log(str.sx_sunstring(-2)) // in console.log(str.sx_sunstring(-9, 10)) // shine_l console.log(str.sx_sunstring(5, 1)) // unsh
Promise 篇
52、all
- 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
- 如果所有 Promise 都胜利,则返回胜利后果数组
-
如果有一个 Promise 失败,则返回这个失败后果
function all(promises) {const result = [] let count = 0 return new MyPromise((resolve, reject) => {const addData = (index, value) => {result[index] = value count++ if (count === promises.length) resolve(result) } promises.forEach((promise, index) => {if (promise instanceof MyPromise) { promise.then(res => {addData(index, res) }, err => reject(err)) } else {addData(index, promise) } }) }) } 53、race
- 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
-
哪个 Promise 最快失去后果,就返回那个后果,无论成功失败
function race(promises) {return new MyPromise((resolve, reject) => { promises.forEach(promise => {if (promise instanceof MyPromise) { promise.then(res => {resolve(res) }, err => {reject(err) }) } else {resolve(promise) } }) }) } 54、allSettled
- 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
-
把每一个 Promise 的后果,汇合成数组,返回
function allSettled(promises) {return new Promise((resolve, reject) => {const res = [] let count = 0 const addData = (status, value, i) => {res[i] = { status, value } count++ if (count === promises.length) {resolve(res) } } promises.forEach((promise, i) => {if (promise instanceof MyPromise) { promise.then(res => {addData('fulfilled', res, i) }, err => {addData('rejected', err, i) }) } else {addData('fulfilled', promise, i) } }) }) } 55、any
any 与 all 相同
- 接管一个 Promise 数组,数组中如有非 Promise 项,则此项当做胜利
- 如果有一个 Promise 胜利,则返回这个胜利后果
-
如果所有 Promise 都失败,则报错
function any(promises) {return new Promise((resolve, reject) => { let count = 0 promises.forEach((promise) => { promise.then(val => {resolve(val) }, err => { count++ if (count === promises.length) {reject(new AggregateError('All promises were rejected')) } }) }) }) } } 56、finally
- 接管一个回调函数,但无参数接管
-
无论成功失败状态,都会执行 finally
Promise.prototype.finally = function(callback) { return this.then(res => {callback() return res }, err => {callback() throw err }) } 结语
如果你感觉此文对你有一丁点帮忙,点个赞,激励一下林三心哈哈。或者能够退出我的摸鱼群 想进学习群,摸鱼群,请点击这里摸鱼,我会定时直播模仿面试,答疑解惑