前端基础打卡1-this指针&闭包&作用域

95 阅读3分钟

记录一下前端学习笔记,每天打卡!!

目标:

必知必会: js | 布局样式 | 客户端 | 技术栈

加分项:工具(CI/CD等) 热门模块工程化

进阶:模式 实战/算法

实战项目统一模板:做完的项目都需要自己再思考下下面的模板

业务层:modules network adapter

工程化层 :webpack plugins output

基础:ci/cs util/e2e vue/react monitor

开始第一天知识学习

变量提升&作用域链

- 变量提升

var和function都存在变量提升

相同点:都是提升声明,未执行

不同点:函数提升的优先级更高,且不会被变量声明覆盖,但是值可以被变量赋值后覆盖

题目:

let a = 'global'
function course() {
    let b = 'zhaowa'

    session()
    function session() {
        let c = 'session'

        teacher()
        function teacher() {
            // let d = 'yy'
            console.log('ds', d)
            var d = 'yy'  // 变量提升 & 变量提升范围:当前作用域

            console.log('d', d); // 作用域生效
            console.log('b', b); // 作用域向上查找
        }
    }
}

course()

// ***********************************
// 提升优先级的问题 => 函数会需要变量
// 变量 函数同时提升时
//  提升维度:变量优先
//  执行维度:函数先打印出来

function test() {}

// ***********************************
// 结论:函数天然的隔离方案 => 模块化
if (true) {
    let e = 111
    var f = 222
}
console.log(e, f)

补充:

  1. 块级作用域:非函数区域都称为块级作用域
  2. var可以忽略块级作用域,let对所有作用域都起作用

总结:

  1. 对于作用域链,可以直接通过创建态来定位
  2. 手动取消全局作用域,使用块级作用域+let/const(可以利用块级作用域区做性能优化)

- this指针&上下文

  1. 函数直接调用 - this指向是window
function foo() {
    console.log('函数内部this', this)
}

foo()
  1. 隐式绑定-this指向的是最后的调用的对象!如果没有找到直接的调用对象,this指向的是全局window
function fn() {
    console.log('隐式绑定', this.a)
}

const obj = {
    a: 1,
    fn
}

obj.fn = fn
obj.fn()

如何改变this指向:

  1. 使用apply bind call来修改this指针
  2. 直接将函数赋值为需要指定this对象的函数

补充:

  1. call和apply区别:传参不同,call是依次传入,apply是数组传入
  2. bind和call,apply区别:bind返回的是一个新的函数,call和apply是调用后立即执行函数

手写题

解题思路:1.说明原理-写注释。 2.根据注释-补齐代码

  • 手写bind
  // 1. 需求手写bind=>bind存放位置(挂载)=>Function.prototype
    Function.prototype.newBind = function () {
      // 2. bind是什么?=>改变上下文=>传入参数:newThis + args1~argsn
      const _this = this;
      const args = Array.prototype.slice.call(arguments);
      const newThis = args.shift();
      // 3. bind要什么?=>返回可以执行函数=>上下文被改变了的原函数(原函数参数不变)
      return function () {
        return _this.newApply(newThis, args);
      };
    };
    Function.prototype.newApply = function (context) {
      context = context || window;

      context.fn = this;

      let result = arguments[1] ? context.fn(...arguments[1]) : context.fn();

      delete context.fn;

      return result;
    };

    // *********测试1**********
    const ob1 = {
      a: 1,
      fn() {
        console.log(this.a);
      },
    };
    const ob2 = {
      a: 2,
      fn() {
        console.log(this.a);
      },
    };
    ob1.fn.newBind(ob2)(); 

上面说了上下文作用域的问题,但是我们如何突破作用域呢?闭包!

闭包

什么是闭包?

闭包是只有权访问另一个函数作用域的变量的函数。 举个例子:

function mail() {
    let content = 'xin'
    return function() {
        console.log(content)
        return content
    }
}
const envelop = mail()
envelop()

总结:函数外部可以通过闭包的形式突破作用域的限制,来获取内部局部变量。所以闭包是模块通信的桥梁,是js模块化的雏形。