SOURCE

//手写call函数
//判断调用对象是否为函数
//判断传入上下文是否存在,不存在则为window
//截取第一个参数后的所有参数
//将函数作为上下文对象的属性
//使用上下文对象调用方法并返回结果
//删除刚才新增的属性
//返回结果
Function.prototype.mycall = function(context){
    //判断调用对象(必须是函数调用)
    if(typeof this !== "function"){
        console.error("type error");
    }
    //获取参数
    let args = [...arguments].slice(1);
        result = null;
    //判断context是否传入,没有的话设置为window
    context = context || window;
    //将调用函数设置为对象的方法
    context.fn = this;
    //执行函数
    result = context.fn(...args);
    //删除属性
    delete context.fn;
    return result;
}

//手写bind
//判断调用对象是否为函数
//保存当前函数的引用,获取其余传入参数值
//创建一个函数返回
//函数内部使用apply绑定函数调用,判断函数作为构造函数的情况,
//这时候需要传入当前函数的this给apply调用,其余都是指定上下文
//
Function.prototype.myBind = function(context){
    //判断是否为函数
    if(typeof this !== "function"){
        throw new TypeError("error");
    }
    //获取参数
    var args = [...arguments].slice(1);
        fn = this;
    return function Fn(){
        //根据调用方式,传入不同绑定值
        return fn.apply(
            this instanceof Fn ? this : context,
            args.concat(...arguments)
        )
    }
}

//手写apply
Function.prototype.myApply = function(context){
    //判断调用对象是否为函数
    if(typeof this !== "function"){
        throw new TypeError("error!")
    }
    let result = null;
    //判断context是否存在,未传入则设置为window
    context = context || window;
    //将函数设置为对象
    context.fn = this;
    if(arguments[1]){
        result = context.fn(...arguments[1]);
    }else{
        result = context.fn()
    }
    //删除属性
    delete context.fn;
    return result;
}

//手写ajax
//asyncchronous javascript and xml
//创建步骤:创建xmlhttprequest
//在对象上用open方法创建一个http请求(参数:请求方法,请求地址,是否异步,用户认证信息)
//setRequestheader 添加信息和监听函数
//XMLhttprequest有5个状态,改变时触发onReadystateChange
//4:服务器接受完成, 2、3:返回正常
//response更新页面
//调用sent方法向服务器发起请求

const SERVER_URL = "/server";
let xhr =  new XMLHttpRequest();

//创建http请求
xhr.open("GET", SERVER_URL, true);
//设置状态监听函数
xhr.onreadystatechange = function(){
    if(this.readyState !== 4){
        return;
    }
    //请求成功
    if(this.readyState === 200){
        handle(this.response)
    }else{
        //输出错误信息
        console.error(this.statusText)
    }

    //设置请求失败时的监听函数
    xhr.onerror = function(){
        console.log(this.statusText);
    }

    //设置请求头信息
    xhr.responseType = "json";

    xhr.setRequestHeader("Accept","application/json");

    //send方法发送http请求
    xhr.send(null);

}

//实现深拷贝
//深浅拷贝区别:浅:把对象属性复制到另一对象,应用类型则把地址复制给对象
//深:遇到属性值为引用类型,新建一个引用类型并赋值,所以将获得一个新的应引用类型
//属性里边存在函数或者symbol时会转换失败
//JSON.parse.(JSON.stringify(obj)):先序列化再反序列化还原,但对存在函数和symbol的对象不行
let obj1 = {
       a:0,
       b:{
           c:0
       } 
}
let obj2 = JSON.parse(JSON.stringify(obj1));
obj1.a = 1;
obj1.b.c = 1;
console.log(obj1);
console.log(obj2);//修改obj1的内容2不会改变

//实现数组的乱序输出
//取出数组的第一个元素,随机产生一个随机值与这个元素进行交换
//再次取出数组第二个元素,产生一个除了索引值为1以外的索引值,将第二个元素与该索引值对应的元素进行交换
//每一个元素重复操作
var arr = [1,2,3,4,5,6,7,8,9,10]
for(var i=0;i<arr.length;i++){
    const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
    //交换位置
    [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
}
console.log(arr)

//实现数组扁平化
//递归实现,遍历每一个元素,如果遇到数组就继续往下遍历,知道全部输出为止
let arr = [1,[2,[3,4,5]]];
function flatton(arr){
    let result = [];
    for(let i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            //是数组则进入递归
            result = result.concat(flatton(arr[i]));
        }else{
            result.push(arr[i])
        }
    }
    return result
}
flatton(arr);
//reduce函数迭代
function flatton(arr){
    return arr.reduce(function(prev, next){
        return prev.concat(Array.isArray(next) ? flatton(next) : next)    
    },[])//立即执行函数
}
//扩展运算符实现


//实现数组去重
//ES6
const array = [1,2,3,4,5,6,7,8,8,8,7]
Array.from(new Set(array))
//ES5
function uniqueArray(array){
    let map = {};
    let res = [];
    for(var i = 0;i<array.length;i++){
        if(!map.hasOwnProperty([array[i]])){
            map[array[i]] = 1;
            res.push(array[i])
        }
    }
    return res;
}

//实现 add(1)(2)(3)
//函数科里化
//粗暴版
function add(a){
    return function(b){
        return function(c){
            return a+b+c
        }
    }
}
console.log(a+b+c)
//函数科里化
var add = function(m){
    var temp = function(n){
        return add(m+n)
    }
    temp.toString = function(){
        return m;
    }
    return temp;
}
console.log(add(3)(4)(5))
//参数长度不固定
function add(...args){
    return args.reduce((a,b) => a+b)
}
function curring(fn){
    let args = [];
    return function temp(...newArgs){
        if(newArgs.length){
            args = [
                ...args,
                ...newArgs
            ]
            return temp
        }else{
            let val = fn.apply(this, args)
            args = []//保证再次调用时为空
            return val
        }
    }
}
//ES5求参数和
function sum(){
    let sunm = 0;   
    Array.prototype.forEach.call(arguments, function(item){
        sum += item * 1;
    })
}
//ES6求参数和
function sum(...nums){
    let sum = 0;
    nums.forEach(function(item){
        sum += item * 1;
    })
    return sum
}


console 命令行工具 X clear

                    
>
console