前端

71 阅读1分钟

bind函数

<script>
    function fn(a,b,c,d){
        console.log(this);
        console.log(a,b,c,d);

        return "this is return"
    }
    // x=100 第一个参数是我想要改的this   原this是window
    // 后面 是要传的参数
    // const cb  = fn.bind({x:100},1,2,3);
    // console.log(cb());

    // 手写bind
    // mybind定义到function的prototype身上
    Function.prototype.mybind = function(){
        const fn = this; // this就是fn,把fn存一下

        // {x:100},[1,2,3]   slice可以切分一个数组,属于把arguments(类数组)切成一个真正的数组
        const arg = Array.prototype.slice.call(arguments);
        const _this = arg.shift();

        // 返回一个函数
        return function(){
            // function.apply(obj,args)方法可以接收两个参数:
            // (1) obj:这个对象将代替function类里this对象
            // (2) args:这个是数组,他将作为参数传给function(args-->arguments)
            return fn.apply(_this,arg); // 改变this用的apply
        }
    }
    const cb  = fn.mybind({x:900},1,2,3,4);
    console.log(cb())
</script>

闭包和闭包的使用场景

  • 概念:闭包是作用域的一种特殊应用
  • 触发闭包的情况:
    1. 函数当做返回值被返回
    2. 函数当作参数被传递
    3. 自执行匿名函数
  • 闭包的应用:
    1. 隐藏变量
    2. 解决for i的问题
  • 作用域:全局作用域,局部作用域
  • 自由变量:不在自己作用域里的变量,就是自由变量,自由变量的值,在函数定义的地方向上层作用域查找,与函数调用位置无关。
    const a  = 100; // 全局变量
    function fn() {
        console.log(a); // 自由变量的值需要去函数定义的上层作用域去寻找
    }
    1. 函数当做返回值被返回
    function fn(){
            const a = 1;
            return function (){
                console.log(a);
            }
        }
    const a = 5;
    const cb = fn();
    cb();
    2. 函数当做参数传递
    function fn(cb){
        const a = 100;
        cb();
    }
    const a = 500;
    fn(function(){
        console.log(a);
    });
    3. 自执行匿名函数
    (function(index){
        console.log(index);
    }(10))
    <button>0</button>
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>
    const aBtn = document.getElementsByTagName("button");
    for(var i=0;i<aBtn.length;i++){
        (function(index){
            aBtn[i].onclick = function(){
                console.log(index);
            }
        })(i);
    } //匿名函数
    // for(let i=0;i<aBtn.length;i++){
    //     aBtn[i].onclick = function(){
    //         console.log(i);
    //     }
    // }
 // 隐藏变量
    function fn(){
        const data = {};
        return {
            // 设置属性的一种方法(是通过参数的形式传递)
            set: function(key,val){
                data[key]=val
            },
            // 获得属性的一种方法(不带任何参数)
            get:function(val){
                return data[val]
            }
        }
    }
    const json = fn();
    json.set("age",18);
    console.log(json.get("age"))

Event Loop

  • JaveScript如何执行:
    1. 自上而下,从左到右一行一行执行
    2. 如果有一行报错,后面的代码不执行
    3. 先执行同步代码,在执行异步代码(setTimeout、Ajax)
  • Event Loop 过程
    1. 同步代码,一行一行放在 Call Stack 中执行
    2. 遇到异步,会先“记录”下代码,等待执行时机(setTimeout、Ajax)。时机到了,将之前“记录”的代码放入 Callback Queue
    3. 当 Call Stack 为空(同步代码执行完),Event Loop 开始工作
    4. Event Loop 轮询查找 Callback Queue 中是否有可执行的代码。如果有,将代码移动到 Call Stack 中执行
    5. Event Loop 如果没有找到可以执行代码,则会继续轮询查找
image.png

宏任务和微任务

  • 微任务:Promise、async、await
  • 宏任务:setTiemout、setInterval、Ajax、DOM事件
  • 先执行微任务,后执行宏任务
  • 宏任务、微任务、DOM渲染的关系:
    1. Call Stack 清空,触发Event Loop
    2. 执行微任务
    3. DOM渲染
    4. 执行宏任务

image.png