私房面经1-1 作用域 & 上下文

53 阅读2分钟

1-1

作用域 & 上下文

作用域链

   let a = 'global'
   function course(){
       let b = 'zhangsan'
       
       session()
       function session() {
           let c  = 'session'
           
           teacher()
           
           function teacher() {
               console.log('ds', d)
               
               var d = 'yyu' // 变量提升 && 范围: 当前作用域
               
                console.log('d': d) // 作用域生效
                console.log('b', b) // 作用域向上查找
           }
       }
   
   }

let 具有块级作用域, 没有变量提升

var 具有变量提升, 变量提升的 范围在当前作用域下

执行栈:

image.png

提升优先级问题

函数会需要变量 变量, 函数同时提升时 提升维度: 变量优先 执行维度: 函数先被打印

函数是天然的隔离方案(模块化), if不形成作用域

    if (true) {
        var f =222
    }
    
    console.log(f) // 222
    1. 对于作用域链, 我们可以直接通过创建态去定位链条中的某一环,
    1. 手动取消链条环甚至全局作用域链的时候, 可以利用块级作用域做性能优化

this 上下文 context

  • this 是在执行时动态读取上下文所决定的

函数直接调佣: this指向window

    function foo() {
        console.log('函数内容this', this)
    }
    foo() // window

隐式绑定 - this 的指向是调用堆栈的上一级

    function fn() {
        console.log('隐式绑定', this)
    }
    const obj = {
        a: 1, 
        fn
    }
    obj.fn = fn
    obg.fn()
    

面试题

    const foo = {
        bar: 10,
        fn: function(){
            console.log(this.bar)
            console.log(this)
        }
    }
    
    // 取出
    let fn1 = foo.fn
    
    fn1()  // this 指向window, 看执行时处于哪个环境
    
    // 追问:
    const o1 = {
        text: 'o1',
        fn: function(){
            // 直接使用上下文 => 传统分活
            console.log('o1_this', this)
            return this.text
        }    
    }
    
    const o2 = {
        text: 'o2',
        fn: function() {
            // 部门协助
            console.log('o2_this', this)
            return o1.fn()
        }
    }
    
    const o3 = {
        text: 'o3',
        fn: function(){
            // 直接借人
            console.log('o3_this', this)
            let fn = o1.fn
            return fn()
        }
    
    }
    
    console.log('o1', o1.fn()) // o1
    console.log('o2', o2.fn()) // o1
    console.log('o3', o3.fn()) // window
    
  • 1.在执行函数的时候, 函数执行时调用方上一级 => 上下文
  • 2.公共函数 | 全局调用指向window

显示绑定(bind | apply | call)

    1. call < = > apply 传参不同 依次传入 / 数组传入
    1. bind 返回值不同 (只是改变了传参, 没有执行)
  • 面试: 手写apply & bind
    // 1. 需求: 手写bind => bind位置 => Function.prototype => 原型
    Function.prototype.newBind = function() {
        // 1.2. bind 原理
        const _this = this
        const args = Array.prototype.slice(arguments) // 类数组 伪数组
        const newThis = args.shift()
        
        // 1.3. 返回值不执行, 返回函数
        return function() {
        // 执行核心
            _this.newApply(newThis, args)
        }
        
    }
   // 2. 内层执行
   Function.prototype.newApply = function(context) {
       // 参数兜底
       const context = context || window
       // 临时挂载执行函数
       context.fn = this
       
       let result = argument[1] ? context.fn(...arguments[1]): context.fn()
       
       delete context.fn
       return result
   }
    

追问: 如何突破作用域

闭包

     function mail(){
         let content = '信'
         
         return function(){
             return content
         }
     }
     
     const envelop = mail()
     envelop()