<template>
    <base-container>
        <div class="mb-5 mt-5">
            <el-button
                v-for="(item, index) in functionArray"
                :key="index"
                type="primary"
                @click="item"
                >点击执行{{ item.name }}方法</el-button
            >
        </div>
        <h3>请查看控制台输出与页面源码</h3>
    </base-container>
</template>

<script setup lang="ts">
import { ref } from 'vue';

/**
 * 题目 1. 冒泡排序
 */
function useBubbleSort() {
    const arr = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5];
    const bubbleSort = (arr: number[]): number[] => {
        const arrLength = arr.length - 1;

        for (let i = 0; i < arrLength; i++) {
            for (let j = 0; j < arrLength - i; j++) {
                let temp = arr[j + 1];
                if (arr[j] > arr[j + 1]) {
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        console.log(arr);
        return arr;
    };

    bubbleSort(arr);
}

/**
 * 题目 1. 防抖函数
 * 防抖函数的作用是，当函数被多次调用时，只有当函数执行结束后，才会执行一次，防止函数被频繁调用。
 * 防抖函数的实现原理是，在函数执行的过程中，设置一个定时器，当函数执行结束后，清除定时器，这样就保证了函数只执行一次。
 * 应用场景一般有：
 * 1. 文本输入框的实时搜索功能，用户输入字符后，函数会在输入结束后才执行，防止函数执行过于频繁。
 * 2. 页面滚动时，函数只在页面停止滚动后才执行，防止函数执行过于频繁。
 * 3. 表单提交时，函数只在用户提交表单后才执行，防止函数执行过于频繁。
 * 4. 窗口大小改变时，函数只在窗口大小改变结束后才执行，防止函数执行过于频繁。
 */
function useDebounce() {
    const debounce = (fn, delay) => {
        let timer = null;
        return function (...args) {
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(() => {
                fn.apply(this, args);
            }, delay);
        };
    };

    window.addEventListener(
        'resize',
        debounce(() => {
            console.log('窗口大小改变了');
        }, 200)
    );
}

/**
 * 题目 1. 节流函数
 */

/**
 * 题目 1. 实现new关键字
 */
function useNew() {
    function _new(f: Function, ...args: any[]) {
        let obj: any = {};
        obj.__proto__ = f.prototype;
        f.apply(obj, args);
        return obj;
    }

    function Person(name, age) {
        this.name = name;
        this.age = age;
        this.sayName = function () {
            console.log(this.name);
        };
    }

    const person = _new(Person, '张三', 20);
    console.log(person);
}

/**
 * 题目 1. 改变this指向
 */
function useChangeThis() {
    function Person() {
        console.log(this.name);
        console.log(this.age);
    }

    class Student {
        constructor(
            public name: string,
            public age: number
        ) {
            this.name = name;
            this.age = age;
        }
    }

    Person.apply(new Student('李四', 21));
}

/**
 * 题目 1. 深拷贝
 * Map与Set注意点
 * Map的键是唯一的
 * Set的元素是唯一的
 */
function useDeepClone() {
    function deepClone(obj: any, existMap = new Map()) {
        if (existMap.get(obj)) {
            return existMap.get(obj);
        }

        let newObj = Array.isArray(obj) ? [] : {};
        existMap.set(obj, newObj);
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key], existMap) : obj[key];
            }
        }

        return newObj;
    }

    // 循环引用示例
    let a = { name: 'a', child: null };
    let b = { name: 'b', child: a };
    a.child = b;

    let deepCloneA = deepClone(a);
    deepCloneA.child.child.name = 'c';
    console.log('深拷贝的原始值', a);
    console.log('深拷贝的新值', deepCloneA);
}

/** 拿到script中所有方法 */
const functionArray = ref([useBubbleSort, useDebounce, useNew, useChangeThis, useDeepClone]);
</script>
