实现let

  1. // 加_
  2. for(var _i=0;_i<5;_i++){}
  3. // 立即函数表达式
  4. (
  5. for(var i=0;i<5;i++){}
  6. )()

实现const

  1. // 实现一个const
  2. function myconst(key, value) {
  3. let desc = {
  4. value,
  5. writable: false,
  6. };
  7. Object.defineProperty(window, key, desc);
  8. }
  9. myconst("name", { a: 1 });

实现call、apply、bind

  1. // 实现一个function.call(thisArg, arg1, arg2, ...)
  2. Function.prototype.mycall = function (thisArg, ...args) {
  3. thisArg.fn = this;
  4. return thisArg.fn(...args);
  5. };
  6. // apply
  7. Function.prototype.myapply = function (thisArg, args) {
  8. thisArg.fn = this;
  9. return thisArg.fn(...args);
  10. };
  11. // bind
  12. Function.prototype.mybind = function (thisArg, ...args) {
  13. return this.call(thisArg, ...args);
  14. };

实现new

  1. // 模拟实现new
  2. function myNew(foo, ...args) {
  3. // Object.create()函数的含义:创建一个对象,并让该对象的__proto__指向参数,
  4. // 这里的参数是foo.prototype,意思是指向foo的原型对象
  5. let obj = Object.create(foo.prototype);
  6. let result = foo.apply(obj, args); // 这里obj调用了foo函数,就会被加上foo函数里带有this.xxx的属性,于是就有obj.name, obj.age等
  7. return typeof result === "object" ? result : obj; // 这里的result是调用foo函数所返回的结果,如果该结果是对象,则返回该对象,否则返回上面所创建的对象obj
  8. } // 相当于 let str = new foo();

防抖debounce函数

  1. // 防抖函数
  2. function debounce(fn, wait) {
  3. let timeout = null;
  4. return function () {
  5. let context = this;
  6. let args = arguments;
  7. if (timeout) clearTimeout(timeout);
  8. else {
  9. timeout = setTimeout(() => {
  10. fn.apply(context, args);
  11. }, wait);
  12. }
  13. };
  14. }
  15. // 防抖测试:
  16. function debounceTest(age) {
  17. console.log("防抖测试", this.name, age);
  18. }
  19. let person = {
  20. name: "oneper",
  21. };
  22. debounce(debounceTest, 4000).call(person, 18); // 4秒后:防抖测试, oneper, 18

节流throttle函数

  1. // 节流函数
  2. function throttle(fn, wait) {
  3. let timeout = null;
  4. return function () {
  5. const thisArg = this;
  6. const args = arguments;
  7. if (!timeout) {
  8. setTimeout(() => {
  9. fn(thisArg, args);
  10. timeout = null;
  11. }, wait);
  12. }
  13. };
  14. }

数组扁平化

  1. const arr = [1, [2, 3], [4, [5, 6]]];
  2. // 1.flat(Infinity) -- <(^-^)>
  3. arr.flat(Infinity);
  4. // 2.序列化后正则去全部括号,添左右括号,反序列化 -- <(^-^)>
  5. const str = `[${JSON.stringify(arr).replace(/(\[|\])/g, "")}]`;
  6. JSON.parse(str);
  7. // 3.递归 -- <(^-^)>
  8. function myflat(arr) {
  9. let result = [];
  10. for (const item of arr) {
  11. item instanceof Array
  12. ? (result = result.concat(flat(item)))
  13. : result.push(item);
  14. }
  15. return result;
  16. }
  17. // 4.自创 -- <(^-^)>
  18. JSON.parse(`[${arr.toString()}]`);
  19. // 5.reduce()递归
  20. function myflatSec(arr) {
  21. return arr.reduce((result, cur) => {
  22. return result.concat(cur instanceof Array ? myflatSec(cur) : cur);
  23. }, []);
  24. }
  25. // 6.迭代+展开运算符
  26. function myflatThr(arr) {
  27. while (arr.some(Array.isArray)) {
  28. arr = [].concat(...arr);
  29. }
  30. }

数组去重

数组去重

  1. // 1. 原始办法:双重循环
  2. function unique(arr = []) {
  3. let result = [];
  4. for (let i = 0, arrLen = arr.length; i < arrLen; i++) {
  5. for (let j = 0, resLen = result.length; j < resLen; j++) {
  6. if (arr[i] === result[j]) break;
  7. }
  8. if (j === resLen) {
  9. res.push(arr[i]);
  10. }
  11. }
  12. return res;
  13. }
  14. // 2. 数组方法indexOf
  15. function unique2(arr = []) {
  16. let result = [];
  17. for (let item of arr) {
  18. if (result.indexOf(item) === -1) result.push(item);
  19. }
  20. return result;
  21. }
  22. // 3. 排序后,后不等前则添加
  23. function unique3(arr = []) {
  24. let result = [];
  25. let sortedArr = [...arr];
  26. sortedArr.sort((a, b) => a - b);
  27. for (let i = 0; i < sortedArr.length; i++) {
  28. if (i === 0) result.push(sortedArr[i]);
  29. else if (sortedArr[i] !== sortedArr[i - 1]) result.push(sortedArr[i]);
  30. }
  31. return result;
  32. }

数组乱序

  1. arr.sort(()=>Math.random()-0.5),但不是真正的乱序
  2. 利用洗牌算法思路:
    1. 从数组末尾开始,向前推进,每次随机和数组中一个元素进行交换

      数组最大、最小值

      深拷贝

      ```javascript // 1.递归 function clone(obj) { // 深拷贝的实现, 递归实现 // 是不是有点N叉树遍历的感觉?! let buf; if (obj instanceof Array) { // 若为数组 buf = [] //创建一个空数组来存 let i = obj.length while (i—) { buf[i] = clone(obj[i]) } return buf } else if (obj instanceof Object) { // 若为对象 buf = {} // 创建一个空对象来存 for (let i in obj) { buf[i] = clone(obj[i]) } return buf } else { // 基本数据类型 return (obj) } }

// 2. JSON, 只能用于对象内部没有方法时 JSON.parse(JSON.stringify(obj))

  1. <a name="5ahlZ"></a>
  2. ## 浅拷贝
  3. <a name="ynuOs"></a>
  4. ## 遍历
  5. 1. 数组的遍历:
  6. ```javascript
  7. let arr = [1, 2, 3];
  8. /1. 原始for方法
  9. for (let i = 0; i < arr.length; i++) {
  10. console.log(arr[i]);
  11. }
  12. /2. for...in 也会将数组的属性遍历出来
  13. arr.name = "joy";
  14. for (let item in arr) {
  15. console.log(item); // 0, 1, 2, name
  16. console.log(arr[item]); // 1, 2, 3, joy
  17. }
  18. /3. for...of
  19. arr.name = "joy";
  20. for (let item of arr) {
  21. console.log(item); // 1, 2, 3
  22. }
  1. 对象的遍历: ```javascript let obj = { name: “joy”, age: 18, school: “fzu”, };

/1. for…in for (let item in obj) { console.log(item); // name, age, school console.log(obj[item]); // “joy”, 18, “fzu” }

/2. Object.keys(obj), Object.values(obj), Object.entries(obj) Object.keys(obj).map((item)=>{ console.log(item); // name, age, school })

  1. 3. 类数组的遍历
  2. ```javascript
  3. / for...of
  4. // for...of语句在可迭代对象(包括 Array, Map, Set, String, TypedArray,arguments 对象等等)上创建一个迭代循环

创建对象的几种模式

参考资料:

工厂模式

构造函数模式

与其它函数不同,函数内部使用this,且通过new操作符进行调用,new操作符做了两件事:1. 创建一个对象并将其proto指向该(构造)函数;2. 通过apply方法将该(构造)函数的this指向该对象。注意构造函数和普通函数没有区别,只是任何函数通过new操作符调用就被称为构造函数。
image.png

原型模式

原型模式即将属性和方法下放到函数的原型对象中:如Function.prototype.name = “mode”

原型+构造函数模式组合

ES5实现继承的4种方式

谈到继承,那么自然就会想到谁继承谁,于是就有子类和父类。至少两个以上的角色才能谈“继承”。

1. 原型链继承

直接让子类的原型对象指向父类实例(即可以调用父类的属性、方法,及其原型上的方法),当子类实例找不到对应的属性和方法时,就会往它的原型对象,也就是父类实例上找,从而实现对父类的属性和方法的继承。

  1. Child.prototype = new Parent();
  2. Child.prototype.constructor = Child;

缺点:

  1. 所有Child实例原型都指向同一个Parent实例,因此对某个Child实例的父类引用类型变量修改会影响所有的Child实例
  2. 在创建子类实例时无法向父类构造传参, 即没有实现super()的功能

image.png

2. 构造函数继承

构造函数继承,即在子类的构造函数中执行父类的构造函数,并为其绑定子类的**this**,让父类的构造函数把成员属性和方法都挂到子类的this上去,这样既能避免实例之间共享一个原型实例,又能向父类构造方法传参。

  1. function Parent(name){
  2. this.name = name;
  3. }
  4. function Child(){
  5. Parent.apply(this, args);
  6. }

缺点:父类原型对象上的属性和方法无法被子类使用。

3. 组合式继承

组合使用原型链继承和构造函数继承

  1. function Parent(name){
  2. this.name = name;
  3. }
  4. function Child(){
  5. Parent.apply(this, args);
  6. }
  7. Child.prototype = new Parent();
  8. Child.prototype.constructor = Child;

缺点:期间调用了2次父类,分别是Parent.apply和new Parent()。

4. 寄生组合式继承

对组合式继承的改进:

  1. Child.prototype = Object.create(Parent.prototype)

ES5实现继承与ES6中class对比

Sleep

  1. // 使用定时器, 是异步的, 所以无法堵塞
  2. function sleep(delay) {
  3. setTimeout(function () {}, delay * 1000)
  4. }
  5. console.log('a')
  6. sleep(10)
  7. console.log('b')
  8. // 使用伪死循环堵塞JS单线程
  9. function sleep(delay) {
  10. var start = (new Date()).getTime();
  11. while ((new Date()).getTime() - start < delay * 1000) {
  12. continue
  13. }
  14. }
  15. console.log('a')
  16. sleep(2)
  17. console.log('b')
  18. // await / async
  19. // await则是进行执行顺序控制,每次执行一个await,
  20. // 程序都会暂停等待await返回值,然后再执行之后的await
  21. function sleep(time) {
  22. return new Promise((resolve) => {
  23. setTimeout(resolve, time)
  24. })
  25. }
  26. (async function output() {
  27. console.log(2)
  28. let out = await sleep(2000);
  29. console.log(1);
  30. })()
  31. //Promise
  32. var sleep = (time) => {
  33. return new Promise((resolve) => {
  34. setTimeout(resolve, time)
  35. })
  36. }
  37. sleep(2000).then((res) => {
  38. console.log(res + ' ' + 1)
  39. })

函数柯里化

特点:有参数时,返回一个函数;没有参数时,执行这个函数,得到计算的结果

  1. // 函数的柯里化
  2. // 需求:要实现一个这样的加法函数,使得:add(1,2,3)(1)(2)(3)(4,5,6)(7,8)() === 42
  3. // 分析这个函数的特点: 当这个函数有参数的时候,返回的是一个函数
  4. // 如果没有参数的时候,就会去执行这个函数,得到计算的结果
  5. function add() {
  6. let list = [];
  7. list = list.concat([...arguments]); // 类数组先转为数组
  8. return function () {
  9. // 如果传了参数,则length不为0
  10. if (arguments.length) {
  11. list = list.concat([...arguments]);
  12. return arguments.callee;
  13. } else {
  14. // 否则开始遍历数组,计算结果
  15. return list.reduce((a, b) => {
  16. return a + b;
  17. });
  18. }
  19. };
  20. }
  21. console.log(add(1, 2, 3)(1, 2, 4, 5, 6)());

JS中sort排序的用法

基本用法:arr.sort(),数组中的数字将会转换成字符进行比较,按从小到大排列。默认排序顺序是根据字符串Unicode码点
sort提供一个比较函数function(a,b)。

  1. 不传任何参数,按照字符串Unicode码点进行排序。
  2. 传入参数,可实现数字的升序、降序:
    1. 升序:arr.sort((a,b)=>a-b)
    2. 降序:arr.sort((a,b)=>b-a)
  3. 根据数组中对象的某个属性值进行排序:arr.sort((a,b)=>a.id-b.id)
  4. 根据数组对象中多个属性值进行排序、多条件排序:
    1. var arr6 = [{id:10,age:2},{id:5,age:4},{id:6,age:10},{id:9,age:6},{id:2,age:8},{id:10,age:9}];
    2. arr6.sort(function(a,b){
    3.   if(a.id === b.id){//如果id相同,按照age的降序
    4.     return b.age - a.age
    5.   }else{
    6.     return a.id - b.id
    7.   }
    8. })

将扁平数据转为树状格式

https://blog.csdn.net/qq_37746973/article/details/78662177
假设后端同学通过接口向前端返回了行业信息列表,为了取用方便,我们希望可以将其转换为树状格式,例如:

  1. let list = [
  2. {
  3. parent_ind: "女装",
  4. name: "连衣裙",
  5. },
  6. {
  7. name: "女装",
  8. },
  9. {
  10. parent_ind: "女装",
  11. name: "半身裙",
  12. },
  13. {
  14. parent_ind: "女装",
  15. name: "A字裙",
  16. },
  17. {
  18. parent_ind: "电脑配件",
  19. name: "内存",
  20. },
  21. {
  22. name: "数码",
  23. },
  24. {
  25. parent_ind: "数码",
  26. name: "电脑配件",
  27. },
  28. ];

转化为:

  1. {
  2. "数码": {
  3. "电脑配件": {
  4. "内存" : {}
  5. }
  6. },
  7. "女装" : {
  8. "连衣裙": {},
  9. "半身裙": {},
  10. "A字裙": {}
  11. }
  12. }
  1. function convert_format(data = []) {
  2. const index = {
  3. undefined: {},
  4. };
  5. data.forEach((item) => {
  6. index[item.name] = {};
  7. });
  8. data.forEach((item) => {
  9. index[item.parent_ind][item.name] = index[item.name]; // 对于没有parent_id的项来说, parent_id是undefined
  10. });
  11. return index.undefined;
  12. }
  1. // 解法2
  2. function convert_format(data) {
  3. let groups = {} // 生成个体对象
  4. let tree = {} // 存储最终结果
  5. const getGroup = key => {
  6. if (!Reflect.has(groups, key)) {
  7. Reflect.set(groups, key, {})
  8. }
  9. return Reflect.get(groups, key)
  10. }
  11. for (let item of data) {
  12. let group = getGroup(item.name)
  13. if (Reflect.has(item, 'parent_ind')) { // 有parent_ind属性
  14. let parent = getGroup(item.parent_ind)
  15. Reflect.set(parent, item.name, group)// 存放有parent_ind属性的对象
  16. } else { // 无parent_ind属性
  17. Reflect.set(tree, item.name, group)
  18. }
  19. }
  20. return tree
  21. }

将对象转数组

  1. let items = {
  2. "3/28/20": 81999,
  3. "3/29/20": 82122
  4. }
  5. // 转化为
  6. [
  7. {
  8. time: "3/28/20",
  9. number: 81999
  10. },
  11. {
  12. time: "3/29/20",
  13. number: 82122
  14. }
  15. ]

使用Object.entries:

  1. Object.entries(items).map((entry)=>{
  2. const [time, number] = entry;
  3. return {time, number}; //用到了ES6的简写规则
  4. })

深度遍历转换

  1. [{
  2. codeName: "name1",
  3. codeValue: "value1",
  4. nodeList: [{
  5. codeName: "name11",
  6. codeValue: "value11",
  7. nodeList: [{
  8. codeName: "name111",
  9. codeValue: "value111"
  10. }]
  11. },
  12. {
  13. codeName: "name12",
  14. codeValue: "value12"
  15. }
  16. ]
  17. }, {
  18. codeName: "name2",
  19. codeValue: "value2",
  20. nodeList: [{
  21. codeName: "name21",
  22. codeValue: "value21"
  23. },
  24. {
  25. codeName: "name22",
  26. codeValue: "value22"
  27. }
  28. ]
  29. }]

转换为:

  1. [{
  2. label: "name1",
  3. value: "value1",
  4. children: [{
  5. label: "name11",
  6. value: "value11",
  7. children: [{
  8. label: "name111",
  9. value: "value111"
  10. }]
  11. },
  12. {
  13. label: "name12",
  14. value: "value12"
  15. }
  16. ]
  17. }, {
  18. label: "name2",
  19. value: "value2",
  20. children: [{
  21. label: "name21",
  22. value: "value21"
  23. },
  24. {
  25. label: "name22",
  26. value: "value22"
  27. }
  28. ]
  29. }]

我的解法:

  1. const dfsBasedTransform = (arr, type) => {
  2. let obj = {};
  3. let result = [];
  4. arr.map((item) => {
  5. if (item.codeName) obj.label = item.codeName;
  6. if (item.codeValue) obj.value = item.codeValue;
  7. if (item.nodeList)
  8. obj.children = dfsBasedTransform(item.nodeList, "object");
  9. result.push(obj);
  10. });
  11. if (type === "array") return result;
  12. else if (type === "object") return obj;
  13. };

数据过滤与转换

  1. [ [true, 'value1'], [false, 'value2']]
  2. ==>
  3. [{ value: 'value1' }]

我的解法:

  1. const normalizeData = (arr = []) => {
  2. return arr.reduce((pre, cur) => {
  3. const [key, value] = cur;
  4. if (key) return pre.concat({ value });
  5. return pre;
  6. }, []);
  7. };