关于作用域以及this

69 阅读2分钟

作用域

作用域

  1. 对于作用域链, 我们可以可以通过创建态区定位快链条中的某一环
  2. 手动取消链条环甚至全局作用的时候,可以利用块级作用域做性能优化
  3. 函数和变量做作用域提升,变量优先,(函数依赖变量), 最后执行函数(先声明变量,在声明函数,函数将变量覆盖),注意: 赋值不会被提升,提升的永远是声明
console.log(a); // 此时a = function, a()可执行,a() => 'function'
var a = 1;
var a = function () {
  console.log("function");
};

if (true) {
  // 只有函数可以天然隔离作用域,函数是天然的隔离方案 => 模块化
  var f = "123";
  // const let 具有块级作用域的,下方不可打印,只作用于当前作用域
  let e = "456";
}
console.log(f, e); // ==> '123' ERROR: e is not defined

this 上下文 context 动态分析

函数直接调用

// 全局函数,全局函数的作用域是window, this上下文表示的是window
function foo() {
  console.log(this); // window
}
foo();

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

function foo() {
  console.log("隐式绑定", this);
}

const obj = {
  a: 1,
  foo,
};

obj.foo = foo;
obj.foo();

// 隐式绑定 {a: 1, foo: ƒ}

面试题

// 面试题:
const obj = {
  a: 1,
  foo: function () {
    console.log(this); // => window
  },
};
let foo1 = obj.foo;
// 此时执行上下文是全局的foo1
foo1();
// => window

显式绑定 this (bind | apply | call)

  1. call 和 apply 的不同 ( call 参数依次传入,apply 参数通过数组传入 ), bind 返回值是个函数
  2. 手写 apply bind
// 需求:手写bind => bind位置 => funciton.Prototype => 原型
Function.Prototype.myBind = function () {
  // 1.1 bind 原理
  const _this = this;
  // 获取传参
  const args = Array.prototype.slice.call(arguments);
  const newThis = args.shift();

  // 1.2 返回值不执行 => 返回函数
  return function () {
    // 执行的核心
    return _this.myApply(newThis, args);
  };
};

// apply
Function.prototype.myApply = function (context) {
  // 参数兜底
  context = context || window;

  // 临时挂载函数
  context.fn = this;

  let result = arguments[1] ? context.fn(...arguments) : context.fn();
  delete context.fn;
  // 返回
  return result;
};