部分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.prototypeperson的原型链上,返回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));

你可能感兴趣的:(javascript,前端,vue.js)