部分JS原生方法手写
2022/2/5 23:44:48
本文主要是介绍部分JS原生方法手写,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
部分JS原生方法手写
Array
let arr = [{ name: '科比', num: 24 }, { name: '詹姆斯', num: 23 }, { name: '保罗', num: 3 }, { name: '威少', num: 1 } ]
forEach
对数组每一项元素进行操作,改变原数组
Array.prototype.myForeach = function (fn) { for (let i = 0; i < this.length; i++) { fn(this[i], i) } } arr.myForeach((val, index) => { console.log('val', val, 'index', index); }) arr.forEach((val, index) => { console.log('val', val, 'index', index); })
map
对数组每一项元素进行操作,返回新数组,不改变原数组
Array.prototype.myMap = function (fn) { let a = [] for (let i = 0; i < this.length; i++) { a.push(fn(this[i], i, this)) } return a } console.log(arr.myMap((item, index, arr) => item.num * 2)); console.log(arr.map((item, index, arr) => item.num * 2));
filter
返回所有满足条件元素组合的新数组,不改变原数组
Array.prototype.myFilter = function (fn) { let a = [] for (let i = 0; i < this.length; i++) { fn(this[i], i, this) ? a.push(this[i]) : '' } return a } console.log(arr.filter(item => item.num > 4)); console.log(arr.myFilter((item, index, arr) => item.num > 4))
every
当所有元素满足条件时,返回true,否则false,不改变原数组
Array.prototype.myEvery = function (fn) { let a = 0 for (let i = 0; i < this.length; i++) { fn(this[i], i, this) ? a++ : '' } return a === this.length } console.log(arr.every((item, index, arr) => item.num > 0)); console.log(arr.myEvery((item, index, arr) => item.num > 0));
some
只要有一项元素满足条件时,返回true,否则false,不改变原数组
Array.prototype.mySome = function (fn) { //方法1 let a = 0 for (let i = 0; i < this.length; i++) { fn(this[i], i, this) ? a++ : '' } return !!a //方法2 for (let i = 0; i < this.length; i++) { if (fn(this[i], i, this)) return true } return false } console.log(arr.some((item, index, arr) => item.num > 4)) console.log(arr.mySome((item, index, arr) => item.num > 4))
reduce
累加器,返回最终结果,不改变原数组
Array.prototype.myReduce = function (fn, val) { for (let i = 0; i < this.length; i++) { val = fn(val, this[i], i, this) } return val } console.log(arr.reduce((val, item, index, arr) => val + item.num, 0)) console.log(arr.myReduce((val, item, index, arr) => val + item.num, 0))
findIndex
数组中有满足条件的元素时,返回该元素的索引,否则返回-1,不改变原数组
indexOf
需要具体值
Array.prototype.myFindIndex = function (fn) { for (let i = 0; i < this.length; i++) { if (fn(this[i], i, this)) return i } return -1 } console.log(arr.findIndex((item, index, arr) => item.name === '威少')) console.log(arr.myFindIndex((item, index, arr) => item.name === '威少'))
find
返回满足条件的元素,否则返回undefinded,不改变原数组
Array.prototype.myFind = function (fn) { for (let i = 0; i < this.length; i++) { if (fn(this[i], i, this)) return this[i] } return undefined } console.log(arr.find((item, index, arr) => item.name === '科比')); console.log(arr.myFind((item, index, arr) => item.name === '科比'));
fill
用指定元素填充数组中指定的元素,改变原数组
Array.prototype.myFill = function (val, start, end) { //初始值为负时,返回原数组 if (start < 0) return this //超出长度时,设置为末元素 let final = end < this.length ? end : this.length for (let i = start; i < final; i++) { this[i] = val } return this } console.log(arr.fill('jzy', 1, 3)) console.log(arr.myFill('jzy', 1, 3))
includes
判断数组中是否有给出的元素,若有则返回true,否则为false,能够判断NaN
,不改变原数组
Array.prototype.myIncludes = function (val) { for (let i = 0; i < this.length; i++) { if (String(this[i]) === String(val)) return true } return false } console.log([1, 2, 3, 4, NaN].includes(NaN)) console.log([1, 2, 3, 4, NaN].myIncludes(NaN))
join
用指定元素将数组拼接为字符串,不改变原数组
Array.prototype.myJoin = function (val) { let str = '' for (let i = 0; i < this.length; i++) { i == this.length - 1 ? str += String(this[i]) : str += String(this[i]) + val } return str } console.log([1, 2, 3, 4, NaN].join('*')); console.log([1, 2, 3, 4, NaN].myJoin('*'));
flat
展开多重数组,展开次数为传入参数,不改变原数组
Array.prototype.myFlat = function (val) { //默认次数为1 val = Number(val) ? Number(val) : 1 let arr = [] //当参数大于需要展开次数时,返回完全展开的数组 while (!this.some(item => Array.isArray(item))) { return this } //展开一次数组 this.forEach(item => { Array.isArray(item) ? arr = arr.concat(item) : arr.push(item) }) //递归实现指定次数展开 return val === 1 ? arr : arr.myFlat(--val) } console.log([1, 2, 3, 4, [5, 6, [7, 8, [9, 0]]]].flat(2)) console.log([1, 2, 3, 4, [5, 6, [7, 8, [9, 0]]]].myFlat(2))
splice
截取指定长度的元素,返回截取元素组成的数组,在原数组中删除截取元素,并插入指定元素
Array.prototype.mySplice = function (x = this.length + 1, y = this.length, ...args) { //处理x,y x = Math.floor(x) y = Math.floor(y) x = x < 0 ? this.length + x : x x = x < 0 ? 0 : x y = x + y <= this.length ? y : this.length - x let arr = [] if (x < this.length && y >= 0) { let arr_ = [] for (let i = 0; i < this.length; i++) { //原数组插入 if (x === i && !y) { for (let i = 0; i < args.length; i++) { arr_.push(args[i]) } } //原数组保留保留 if (x > i || !y) arr_.push(this[i]) //删除、返回对象 if (x === i && y) { arr.push(this[i]) x++ y-- } } //清空this,重新赋值 this.length = 0 for (let i = 0; i < arr_.length; i++) { this[i] = arr_[i] } } return arr } let arr = [...str] let arr2 = [...str] console.log(arr.mySplice()); console.log(arr); console.log(arr2.splice()); console.log(arr2);
Object
Tips:
对对象使用forin
方法时,会遍历原型链上的自定义属性
let obj = { name: 'J1nzy', age: 22, sex: '男', hobby: { food: '糯米藕' } }
entries
将对象拆分为键值对的数组形式
Object.prototype.myEntries = function (obj) { let arr = [] for (const key in obj) { (Object.hasOwnProperty.call(obj, key)) && arr.push([key, obj[key]]) } return arr } console.log(Object.entries(obj)) console.log(Object.myEntries(obj))
fromEntries
将键值对的数组转化为对象形式
Object.prototype.myFromEntries = function (arr) { let obj = {} for (let i = 0; i < arr.length; i++) { let [key, value] = arr[i] obj[key] = value } return obj } console.log(Object.fromEntries([ ['name', 'J1nzy'], ['age', '22'] ])) console.log(Object.myFromEntries([ ['name', 'J1nzy'], ['age', '22'] ]))
keys
返回以对象每个键组成的数组
Object.prototype.myKeys = function (obj) { let arr = [] for (const key in obj) { Object.hasOwnProperty.call(obj, key) && arr.push(key) } return arr } console.log(Object.keys(obj)) console.log(Object.myKeys(obj))
values
返回以对象每个值组成的数组
Object.prototype.myValues = function () { let arr = [] for (const key in obj) { Object.hasOwnProperty.call(obj, key) && arr.push(obj[key]) } return arr } console.log(Object.values(obj)) console.log(Object.myValues(obj))
instanceOf
若Father.prototype
在person
的原型链上,返回true,否则为false
function Father(){} function Son() {} Son.prototype.__proto__ = Father.prototype let person = new Son() function myInstanceOf(father,son) { while (son.__proto__) { if (son.__proto__ === father.prototype) return true son = son.__proto__ } return false } console.log(myInstanceOf(Father,person)) console.log(person instanceof Father)
is
判断两个对象是否相等,相等则返回true,否则false
Object.prototype.myIs = function (x, y) { if (x === y) { //处理+0和-0 return x !== 0 || 1 / x === 1 / y; } else { //处理NaN return x !== x && y !== y; } } let a = { i: 1 } let b = { i: 1 } let c = a console.log(Object.myIs(a, b));//false console.log(Object.myIs(a, c));//true
assign
将第一个对象改变为一个拼接后的对象,若有相同属性,以后面为准,并作为返回值
Object.prototype.myAssign = function (arr, ...arrs) { if (arr === null || arr === undefined) throw ('添加类型错误') for (let i = 0; i < arrs.length; i++) { for (const key in arrs[i]) { if (arrs[i].hasOwnProperty(key)) { arr[key] = arrs[i][key] } } } return arr } let a = { a: 1, b: 2 } let b = { a: 3, c: 4 } let c = { a: 4, d: 5 } console.log(Object.myAssign(a, b, c) === a);//true console.log(Object.myAssign(a, b, c)); console.log(a);
Function
let mei = new Person('小美') let li = new Person('小丽') function Person(name) { this.name = name } Person.prototype.showName = function (age,a) { console.log(this.name + age + '岁了' + a); }
call
改变this的指向,默认为window,传参为队列
Function.prototype.myCall = function (caller, ...args) { caller = caller || window //唯一,避免与属性重复 let fn = Symbol() caller[fn] = this return caller[fn](...args) } mei.showName.myCall(li, 16) li.showName.myCall(mei, 18)
apply
改变this的指向,默认为window,传参为数组
Function.prototype.myApply = function (caller, args) { caller = caller || window //唯一,避免与属性重复 let fn = Symbol() caller[fn] = this return caller[fn](...args) } mei.showName.apply(li, [16,12]) mei.showName.myApply(li, [16,12])
bind
返回一个改变this指向后函数,该函数返回值不变
Function.prototype.myBind = function (binder, ...args) { binder = binder || window let fn = Symbol() binder[fn] = this return function () { return binder[fn](...args) } } Object.prototype.test = function (...args) { console.log(this.name); console.log(args); return '美' } let mei = { name: '小美' } let li = { name: '小丽' } console.log(mei.test.bind(li, 1, 2, 3)()); console.log(mei.test.myBind(li, 1, 2, 3)());
String
let str = '1234567890'
substr
截取指定长度的字符串,不改变原字符串
String.prototype.mySubstr = function (x = 0, y = this.length) { //处理下x,y x = Math.floor(x) y = Math.floor(y) x = x < 0 ? this.length + x : x x = x < 0 ? 0 : x y = y < 0 ? 0 : y let str = '' //截取字符并不超出字符串 while (y && x < this.length) { str += this[x] x++ y-- } return str } console.log(str.substr(-3, 5)); console.log(str.mySubstr(-3, 5));
substring
截取指定位置的元素并返回其组成的数组,x>y
时,对调,负值置零,不改变原数组
String.prototype.mySubstring = function (x = 0, y = this.length) { //处理下x,y x = Math.floor(x) y = Math.floor(y) [x, y] = x > y ? [y, x] : [x, y] x = x < 0 ? 0 : x let str = '' //当y大于字符串长度时,设置为字符串长度,y<0时返回空字符串 while (x < (y = y > this.length ? this.length : y) && y >= 0) { str += this[x] x++ } return str } console.log(str.substring(4, -1)); console.log(str); console.log(str.mySubstring(-2, -1));
slice
截取指定位置的元素并返回其组成的数组,负值会处理,不改变原数组
String.prototype.mySlice = function (x = 0, y = this.length) { //处理下x,y x = Math.floor(x) y = Math.floor(y) x = x < 0 ? this.length + x : x y = y < 0 ? this.length + y : y x = x < 0 ? 0 : x y = y < 0 ? 0 : y let str = '' //当y大于字符串长度时,设置为字符串长度 while (x < (y = y > this.length ? this.length : y)) { str += this[x] x++ } return str } console.log(str.slice(1, 10)); console.log(str.mySlice(1, 13));
这篇关于部分JS原生方法手写的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16Vue3资料:新手入门必读教程
- 2024-11-16Vue3资料:新手入门全面指南
- 2024-11-16Vue资料:新手入门完全指南
- 2024-11-16Vue项目实战:新手入门指南
- 2024-11-16React Hooks之useEffect案例详解
- 2024-11-16useRef案例详解:React中的useRef使用教程
- 2024-11-16React Hooks之useState案例详解
- 2024-11-16Vue入门指南:从零开始搭建第一个Vue项目
- 2024-11-16Vue3学习:新手入门教程与实践指南
- 2024-11-16Vue3学习:从入门到初级实战教程