//01、封装一个方法,要求把给定的任意的 IP 字符串,转化成 32 位的二进制字符串。
        function ipToSting32(ip) {
            return ip.split('.').map(item => Number(item)).reduce((a, b) => {
                return a + b.toString(2)
            }, '')
        }
        console.log(ipToSting32('192.168.72.204'));
//02、求出现次数最多的字符、出现了多少次。helheloawodop
        function moreStr(str) {
            let obj = {}
            for (let i = 0; i < str.length; i++) {
                let char = str.charAt(i)
                if (obj[char]) {
                    obj[char]++
                } else {
                    obj[char] = 1
                }
            }
            let max = 0
            let word = ''
            for (let j in obj) {
                if (obj[j] > max) {
                    max = obj[j]
                    word = j
                }
            }
            return '出现最多的字母是:' + word + ',出现了' + max + '次'
        }
        console.log(moreStr('helheloawodop'));
 //03.封装冒泡排序算法 sortMe()
        function sortMe(arr) {
            for (let i = 0; i < arr.length - 1; i++) {
                for (let j = 0; j < arr.length - i - 1; j++) {
                    if (arr[j] > arr[j + 1]) {
                        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
                    }
                }
            }
            return arr
        }
        console.log(sortMe([12, 23, 14, 1, 2, 4, 6, 8, 2, 9]));

        快速排序
        function quickSort(arr) {
            if (arr.length <= 1) {
                return arr
            }
            // 组件索引
            let middle = Math.floor(arr.length / 2)
            // 中间值
            let midValue = arr.splice(middle, 1)[0]
            let left = []
            let right = []
            for (let i = 0; i < arr.length; i++) {
                if (arr[i] < midValue) {
                    left.push(arr[i])
                } else {
                    right.push(arr[i])
                }
            }
            return quickSort(left).concat([midValue], quickSort(right))
        }
        console.log(quickSort([12, 23, 14, 1, 2, 4, 6, 8, 2, 9]));
//04、使用 Promise 封装 $.ajax,得到 request() 。
        function request(method, url, data) {
            return new Promise((resolve, reject) => {
                var xhr = new XMLHttpRequest();
                var method = method || "GET";
                var data = data || null;
                xhr.open(method, url, true);
                xhr.onreadystatechange = function () {
                    if (xhr.status === 200 && xhr.readyState === 4) {
                        resolve(xhr.responseText);
                    } else {
                        reject(xhr.responseText);
                    }
                }
                xhr.send(data);
            })
        }
      // 05、有哪些数组去重的方法?(至少3种)
        var a = [1, 2, 3, 1, 113, 4, 5, 21, 1];
        console.log([...new Set(a)]);

        a.quc = function () {
            var b = [];
            console.log(this);
            this.forEach((item, index) => {
                if (b.indexOf(item) == -1) {
                    b.push(item)
                }
            })
            return b;
        }

        var b = a.quc()
        console.log(b);


        a.quc2 = function () {
            var this = a.sort((a, b) => a - b)
            console.log(this);
            var b = []
            for (var i = 0; i < this.length; i++) {
                if (this[i] !== this[i + 1]) {
                    b.push(this[i])

                }
            }
            return b;
        }
        var b = a.quc2()
        console.log(b);


        a.quc3 = function () {
            console.log(this);
            for (var i = 0; i < this.length; i++) {
                for (var j = i + 1; j < this.length; j++) {
                    if (this[i] == this[j]) {
                        this.splice(j, 1);
                        j--
                    }
                }
            }
            return this;
        }
        var b = a.quc3()
        console.log(b);

        还可以统计 数组中元素的个数
        a.quc4 = function () {
            var arrry = [];
            var obj = {};
            for (var i = 0; i < this.length; i++) {
                if (!obj[this[i]]) {
                    arrry.push(this[i])
                    obj[this[i]] = 1
                } else {
                    obj[this[i]]++
                }
            }
            console.log(obj);
            return arrry;
        }
        var b = a.quc4()
        console.log(b);



        a.quc5 = function () {
            var array = [];
            for (var i = 0; i < this.length; i++) {
                if (!array.includes(this[i])) {
                    array.push(this[i]);
                }
            }
            return array
        }
        var b = a.quc5()
        console.log(b);


        a.quc6 = function () {
            return this.filter(function (item, index, arr) {
                // 当前元素在原始数组中的第一个索引==当前索引值,否则返回当前元素
                // arr.indexOf()  //只第一次出现的位置  只返回一次
                console.log(arr.indexOf(item));
                return arr.indexOf(item) === index;
            });
        }
        var b = a.quc6()
        console.log(b);
//06、封装一个可以用于深拷贝(深复制)的方法。
        function clone(target) {
            if (target instanceof Array || (target !== null && typeof target === 'object')) {
                const cloneTarget = target instanceof Array ? [] : {}
                for (const key in target) {
                    if (target.hasOwnProperty(key)) {
                        cloneTarget[key] = deepClone2(target[key]) // 对属性值进行递归处理
                    }
                }
                return cloneTarget
            } else {
                return target
            }
        }

        //函数防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。
        //函数节流(throttle):高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。
        //函数节流(throttle)与 函数防抖(debounce)都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。

        //07、封装防抖函数。
        function debounce(fn, delay) {
            var timer = null
            return function () {
                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(fn, delay)
            }
        }
        // test
        function handle() {
            console.log(Math.random())
        }
        window.addEventListener('mousemove', debounce(handle, 1000))

        // 08、封装节流函数。
        // (1) 通过date设定
        function throttle(fn, delay) {
            let timer, start = 0;

            return function () {
                let now = new Date().getTime();
                if (now > start + delay) {
                    fn();
                    start = now;
                }
            }
        }
        // (2) 定时器方案
        function throttle(fn, delay) {
            let timer = null;
            return function () {
                if (!timer) {
                    timer = setTimeout(function () {
                        fn();
                        timer = null;
                    }, delay)
                }
            }
        }


        function handle() {
            console.log(Math.random());
        }
        window.addEventListener("mousemove", throttle(handle, 1000));


        //节流函数的使用场景
        //懒加载、滚动加载、加载更多或监听滚动条位置;
        //百度搜索框,搜索联想功能; 
        //防止高频点击提交,防止表单重复提交;
// 09、详细描述 Vue 完整的生命周期过程。
    // 什么是Vue地生命周期?
    // Vue实例从创建到销毁地过程,即开始创建,初始化数据,编译模板,挂载DOM、渲染,更新、渲染,卸载等过程。
    // Vue各个阶段(钩子函数)的作用/意义?
    // 生命周期中的多个钩子函数给了用户在不同阶段添加代码的机会。
    // 第一次页面加载会触发哪些钩子函数?
    // beforeCreate、created、beforeMount、mounted
    // DOM渲染在什么周期已经完成?
    // mounted
    // created和mounted的区别?
    // created:调用时,此时模板还未渲染,不能操作DOM,主要用来初始化数据;
    // mounted:调用时,此时模板已经渲染成html,可以操作DOM。
    // 09、详细描述 Vue 完整的生命周期过程。
        // 什么是Vue地生命周期?
        // Vue实例从创建到销毁地过程,即开始创建,初始化数据,编译模板,挂载DOM、渲染,更新、渲染,卸载等过程。
        // Vue各个阶段(钩子函数)的作用/意义?
        // 生命周期中的多个钩子函数给了用户在不同阶段添加代码的机会。
        // 第一次页面加载会触发哪些钩子函数?
        // beforeCreate、created、beforeMount、mounted
        // DOM渲染在什么周期已经完成?
        // mounted
        // created和mounted的区别?
        // created:调用时,此时模板还未渲染,不能操作DOM,主要用来初始化数据;
        // mounted:调用时,此时模板已经渲染成html,可以操作DOM。


        // 10、谈一谈你对 MVC / MVP / MVVM 的理解。**
        // MVC把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)
        // 模型(Model):数据库相关的操作、文件的访问和数据结构等。
        // 视图(View):专注于显示,如Web前端(HTML/CSS/Java Script)
        // 控制器(Controller):连接模型和视图,如把视图的请求发送给模型或把数据返回给视图等

        // MVC的实现了视图和模型的分离,避免了视图和模型糅合在一起,当视图改变的时候只要业务逻辑没变不需要改变模型;但是它有一个缺点缺点是因为MVC中的控制器并不能直接更新视图,所以MVC并不能实现视图和模型的完全分离,视图依然依赖模型的数据(数据结构)来显示,也就是说视图依赖模型。



        // MVP是针对MVC的缺点而进行了改进,它把软件系统分为三个基本部分:模型(Model)、视图(View)和展示器(Presenter)
        // 模型(Model):数据库相关的操作、文件的访问和数据结构等。
        // 视图(View):专注于显示,如Web前端(HTML/CSS/Java Script)
        // 展示器(Presenter):连接模型和视图,处理视图的请求并根据模型更新视图。

        // MVP用展示器代替了控制器,而展示器是可以直接更新视图,所以MVP中展示器可以处理视图的请求并递送到模型又可以根据模型的变化更新视图,实现了视图和模型的完全分离




        // MVVM是MVP更进一步的发展,把软件系统分为三个基本部分:模型(Model)、视图(View)和视图模型(ViewModel)
        // 模型(Model):数据库相关的操作、文件的访问和数据结构等。
        // 视图(View):专注于显示,如Web前端(HTML/CSS/Java Script)
        // 视图模型(ViewModel):连接模型和视图,视图模型和视图是双休绑定的。

        // MVVM用视图模型代替了MVP中的展示器,视图模型和视图实现了双向绑定,当视图发生变化的时候视图模型也会发生改变,当视图模型变化的时候视图也随之变化。


        // 总结:MVC/MVP/MVVM都是根据不同的应用需求和应用环境逐步发展而来的,它们都有各自优缺点和适用环境。比如Web开发中因为要跨越网络通讯,如果使用MVP或者MVVM来实现代价是巨大的,因为目前来说网络数据是很珍贵的资源