作用域链/this指向常见面试题

作用域链

  1. 作用域链:通过创建态决定的
  2. 手动取消全局作用域:通过块级作用域
let a = 'global'
console.log(a);//'global'
function course() {
  let b = 'this指向'
  console.log(b);//'this指向'

  session()
  function session() {
    let c = 'this'
    console.log(c);//'this'

    teacher()
    function teacher() {
      let d = 'yy'
      console.log(d);//'yy'

      console.log('test1', b);//'test1' 'this指向'
    }
  }
}

console.log('test2', b)//b is not defined
course()

函数直接调用: this 指向window

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

隐式绑定:this 指向上一级

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

面试题:

const foo = {
  bar: 10,
  fn: function () {
    console.log(this.bar);//undefined
    console.log(this);//window
  }
}

// 取出
let fn1 = foo.fn
// 执行
fn1()

const o1 = {
  text: 'o1',
  fn: function () {
    return this.text
  }
}
const o2 = {
  text: 'o2',
  fn: function () {
    return o1.fn()
  }
}
const o3 = {
  text: 'o3',
  fn: function () {
    let fn = o1.fn
    return fn()
  }
}

console.log('01fn', o1.fn());//o1
console.log('02fn', o2.fn());//o1
console.log('03fn', o3.fn());//undefined ( 因为 this 指向 window )

追问:如何改变this指向:现在要将console.log('o2fn',o2.fn())的结果是o2

const o1 = {
  text: 'o1',
  fn: function () {
    return this.text
  }
}
const o2 = {
  text: 'o2',
  fn: o1.fn
}

console.log('01fn', o1.fn());//o1
console.log('02fn', o2.fn());//o2

new:this指向的是new之后得到的实例

class Course {
  constructor(name) {
    this.name = name
    console.log('构造函数内的this', this); // course
  }
  test() {
    console.log('类方法中的this', this); // course
  }
}

const course = new Course('yy')
course.test()

追问:类中同步和异步方法中的this指向有区别吗

class Course {
  constructor(name) {
    this.name = name
    console.log('构造函数内的this', this);//course
  }
  test() {
    console.log('类方法中的this', this);//course
  }
  asyncTest() {
    console.log('异步方法外的this', this);//course
    // 普通函数
    setTimeout(function () {
      console.log('异步方法内的this1', this);//window
    }, 100);
    // 箭头函数
    setTimeout(() => {
      console.log('异步方法内的this2', this);//course
    }, 200);
  }
}

const course = new Course('yy')
course.test()
course.asyncTest()

如何突破作用域的束缚:闭包

  • 闭包的应用场景

  1. 函数作为返回值:函数外可以访问函数内部的变量
    function mail() {
      let content = '信'
      return function () {
        console.log(content);
      }
    }
    const envelop = mail()
    envelop()
  2. 函数作为参数
    let content
    function envelop(fn) {
      content = 1
      fn()
    }
    
    function mail() {
      console.log(content);
    }
    envelop(mail)
  3. 函数嵌套:计数器的应用
    let count = 0
    function outerFn() {
      function innerFn() {
        count++
        console.log(count);
      }
      return innerFn
    }
    outerFn()()
  4. 事件处理(异步)
    let lis = document.querySelector('li')
    for (let i = 0; i < lis.length; i++) {
      (function (i) {
        lis[i].onclick = function () {
          console.log(i);
        }
      })(i)
    }
  • 追问:
  1. 立即执行嵌套
    (function immediateA(a) {
      return (function (b) {
        console.log(a);//0
      })(1)
    })(0)
  2. 当立即执行函数遇到块级作用域
    let count = 0;
    (function immediate() {
      if (count === 0) {
        let count = 1
        console.log(count); // 1
      }
      console.log(count); // 0
    })()
  3. 拆分执行
    function createIncrement() {
      let count = 0
    
      function increment() {
        count++
      }
    
      let message = `count is ${count}`
    
      function log() {
        console.log(message);
      }
      return [increment, log]
    }
    
    const [increment, log] = createIncrement()
    
    increment()
    increment()
    increment()
    log() // count is 0
    function createIncrement() {
      let count = 0
    
      function increment() {
        count++
      }
    
      
      function log() {
        let message = `count is ${count}`
    
        console.log(message);
      }
      return [increment, log]
    }
    
    const [increment, log] = createIncrement()
    
    increment()
    increment()
    increment()
    log() // count is 3
  4. 实现私有变量
    function createStack() {
      const items = []
      return {
        push(item){
          items.push(item)
        }
      }
    }
    
    //给外界只暴露一个操作变量items的push方法,会形成对变量的保护

猜你喜欢

转载自blog.csdn.net/m0_56274171/article/details/123421334