笔记:作用域 & 上下文

139 阅读2分钟

变量的生成查找

var bar=1;

var bar=1; var bar 编译器先会查询作用域是否存在变量bar?
作用域
- 存在: 忽略这个变量声明,往下执行
- 不存在: 就在当前作用域生成一个新的变量命名为bar
然后生成bar=1能够被引擎执行的代码
runtime 引擎执行时,会在作用域中查找是存在bar
- 存在: 赋值为1
- 不存在: 去上一层作用域查找

foo, bar, baz其实这些词没有任何意思, 通常当作占位符使用

  • foo: first object oriented 第一个面向对象

  • bar: binary arbitrary reason 任意二进制原因

Scope(作用域)

作用域就是根据变量名称查询变量的规则。

    function foo(){
        var bar = 1;
        function baz(){
           console.log(bar);
        }
        baz();
    }

运行foo(), 打印输出 bar

  1. 在 baz 函数中查找变量 bar
  2. 不存在, 去上一层作用域foo查找
  3. 存在, 获取 foo 中 bar 的值

上下文

this 的指向, 是根据当前的执行上下文动态决定的

  • 在简单调用时, this 默认指向的是 window / global / undefined ( 浏览器 / node / 严格模式 )
  • 在对象调用时,指向的是当前对象
  • 在使用 call / apply / bind 时,指向的是绑定的对象
  • 使用 new 关键字, 指向新创建的对象
    优先级: new > call/apply/bind > 对象调用
  • 箭头函数根据外层的规则确定。
var number = 10; 
var obj = {
    number: 5, 
    fn1: (function () {
        var number;   
        this.number *= 2; 
        number = number * 2;
        number = 3;
        return function () {
            var num = this.number;
            this.number *= 2;
            console.log(num);  
            number *= 3; 
            console.log(number);  
        }
    })()
}

var fn1 = obj.fn1; 
fn1.call(null);  
obj.fn1();
console.log(window.number);
  1. var fn1 = obj.fn1; 由于obj.fn1是IIFE(立即执行函数), 返回一个函数, 形成一个闭包,因为是简单调用, this指向window, this.number *= 2;最外层number变成 20; number = number * 2; number = 3;闭包中变量number赋值为 3;
  2. fn1.call(null);使用call绑定值为null, fn1this指向是window, this.number *= 2;最外层number变成 40; console.log(num);打印输出 20; number *= 3;在词法作用域中查找到闭包变量number并进行计算变成9; console.log(number);打印输出9;
  3. obj.fn1();执行, fn1this指向是obj, console.log(num);打印输出5, number *= 3;闭包变量number并进行计算变成9*3=27, 打印输出27
  4. 此时windownumber 为40,打印输出40

call 简单实现

    Function.prototype.callN = function(context,...rest){
        context.fn = this;
        if(context){
            const result = context.fn(...rest);
            delete context.fn;
            return result;
        }else{
            this(...args)
        }
    }

bind 简单实现

    Function.prototype.bindN=function(context,...rest){
        const fn=this;
        return function(...innerRest){
            const args=[...rest,...innerRest];
            fn.call(context,...args);
            // context.fn = fn;
            // if(context){
           
            // const result= context.fn(...args);
            //     delete context.fn;
            //     return result
            // }else{
            //     this(...args)
            // }
           
         }
    }