js常见函数实现
文章目录
- 一、数组Array
- 1、forEach
- 2、filter
- 3、map
- 4、reduce
- 5、find
- 6、findIndex
- 7、includes
- 8、join
- 二、对象Object
- 1、Object.keys
- 2、深复制
js环境中有很多工具函数,比如es6添加了很多新的属性和方法,这些方法也可以自定义实现,但是官方也提供出来了(这样可以形成规范和一致性),了解为什么要提供这些函数是有必要的。
一、数组Array
公共数据
const inventory = [
{ name: "芦笋", type: "蔬菜", quantity: 5 },
{ name: "香蕉", type: "水果", quantity: 0 },
{ name: "山羊", type: "肉", quantity: 23 },
{ name: "樱桃", type: "水果", quantity: 5 },
{ name: "鱼", type: "肉", quantity: 22 }
];
1、forEach
// 自定义forEach方法
Array.prototype.forEachCustom = function (cb) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
for (let i = 0; i < this.length; i++) {
// this[i], i, this 三个参数分别表示当前元素,索引,数组本身
// 大部分功能函数都是这三个参数和顺序
cb(this[i], i, this);
}
};
// inventory.forEachCustom((item) => { // TEST
// console.log(item.name);
// });
2、filter
// 自定义filter方法
Array.prototype.filterCustom = function (cb) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
const result = [];
for (let i = 0; i < this.length; i++) {
// 返回值只是为了做if判断,不用存储;存储的是满足条件的元素
if (cb(this[i], i, this)) {
result.push(this[i]);
}
}
return result;
};
const resultFilterCustom = inventory.filterCustom((item) => {
return item.quantity >= 6;
});
// console.log("filterCustom", resultFilterCustom); // TEST
3、map
// 自定义map方法
Array.prototype.mapCustom = function (cb) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
const result = [];
for (let i = 0; i < this.length; i++) {
// 将返回值存储起来,最后返回; 当然函数默认返回undefined
result.push(cb(this[i], i, this));
}
return result;
};
const resultMapCustom = inventory.mapCustom((item) => {
if (item.quantity >= 6) {
return item.name;
}
});
// console.log("mapCustom", resultMapCustom); // TEST
4、reduce
// 自定义reduce方法
Array.prototype.reduceCustom = function (cb, initialValue) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
// 每一次循环的结果都会作为下一次循环的初始值; 最后返回出去
let result = initialValue;
for (let i = 0; i < this.length; i++) {
result = cb(result, this[i], i, this);
}
return result;
};
const resultReduceCustom = inventory.reduceCustom((acc, item) => {
return acc + item.quantity;
}, 0);
// console.log("reduceCustom", resultReduceCustom); // TEST
5、find
// 自定义find方法
Array.prototype.findCustom = function (cb) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
for (let i = 0; i < this.length; i++) {
// 返回值只是为了做if判断,不用存储;
// 找到第一个满足条件的元素就返回,找到就停止遍历
// 有点类似于filter,但是只返回第一个满足条件的元素
if (cb(this[i], i, this)) {
return this[i];
}
}
// 如果没有找到,返回undefined
};
const resultFindCustom = inventory.findCustom((item) => {
return item.name === "香蕉";
});
// console.log("findCustom", resultFindCustom); // TEST
6、findIndex
// 自定义findIndex方法
Array.prototype.findIndexCustom = function (cb) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的cb是自定义的回调函数;
if (typeof cb !== "function") {
return;
}
for (let i = 0; i < this.length; i++) {
// 返回索引,找到第一个满足条件的元素就返回,找到就停止遍历
// 很类似于find,但是只返回第一个满足条件的元素的索引
if (cb(this[i], i, this)) {
return i;
}
}
// 如果没有找到,返回-1
};
const resultFindIndexCustom = inventory.findIndexCustom((item) => {
return item.name === "樱桃";
});
// console.log("findIndexCustom", resultFindIndexCustom); // TEST
7、includes
// 自定义includes方法
Array.prototype.includesCustom = function (value) {
for (let i = 0; i < this.length; i++) {
// 这里默认数组是一维数组; 只是单纯判断值是否存在;
// 如果是复杂数据,使用find即可;
if (this[i] === value) {
return true;
}
}
return false;
};
// console.log("includesCustom", [1, 2, 3, 4, 5].includesCustom(2)); // TEST
8、join
// 自定义join方法
Array.prototype.joinCustom = function (separator) {
// 这里的this是数组本身;
if (!Array.isArray(this)) {
return;
}
// 这里的separator是自定义的分隔符;
if (typeof separator !== "string") {
return;
}
let result = "";
for (let i = 0; i < this.length; i++) {
// 这里默认数组是一维数组;
// 这里默认separator是空格;
result += this[i] + separator;
}
// 去掉最后一个分隔符;
return result.slice(0, -1);
};
console.log("joinCustom", [1, 2, 3, 4, 5].joinCustom("-")); // TEST
二、对象Object
1、Object.keys
提供了一个案例,获取属性时的原型链问题
// 简易版继承
const parentFunc = function () {
this.name = "张三";
};
const childFunc = function () {
// 继承父类的属性和方法;构造函数继承;
// 注意调用的时机,会决定实例的属性顺序;比如这里的name属性在age前面
parentFunc.call(this);
// 运行时this指向childFunc实例对象(的内存空间);
this.age = 20;
};
parentFunc.prototype.getName = function () {
return this.name;
};
childFunc.prototype = new parentFunc();
const childObj = new childFunc();
const keysAll = [];
const keysOwn = [];
for (let key in childObj) {
// 自己的属性和原型链上的属性都会遍历出来;
// 原型链继承的所有属性 + Object.prototype 挂载的自定义方法
keysAll.push(key);
if (childObj.hasOwnProperty(key)) {
// 自己的属性才会遍历出来;
keysOwn.push(key);
}
}
console.log("Object.keysCustom", keysAll, keysOwn); // TEST
// 结果:keysAll = ["name", "age", "getName", "keysCustom"];
// 结果: keysOwn = ["name", "age"];
// 自定义Object.keys方法 用于获取对象所有属性名
Object.prototype.keysCustom = function (obj) {
if (typeof obj !== "object" || obj === null) {
return;
}
const result = []; // 用于存储结果
for (let key in obj) {
// hasOwnProperty表示自身的属性,不包括原型链上的属性
if (obj.hasOwnProperty(key)) {
// 相当于循环后存储key
result.push(key);
}
}
return result;
};
const obj = { name: "张三", age: 20, gender: "男" };
// console.log("Object.keysCustom", Object.keysCustom(obj)); // TEST
2、深复制
const data = [
{ name: "张三", age: 20, array: [1, 2, 3] },
{ name: "李四", age: 25, array: [4, 5, 6] }
];
const deepClone = (source) => {
if (typeof source !== "object" || source == null) {
return source;
}
const target = Array.isArray(source) ? [] : {};
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (typeof source[key] === "object" && source[key] !== null) {
target[key] = deepClone(source[key]);
} else {
target[key] = source[key];
}
}
}
return target;
};
console.log("deepCopy", deepClone(data)); // TEST