龙空技术网

JS必知必会: 作用域 | 上下文 this | 闭包

爱码字的小屁孩 97

前言:

此刻大家对“js块级作用域问题”大体比较着重,小伙伴们都需要学习一些“js块级作用域问题”的相关内容。那么小编也在网上网罗了一些对于“js块级作用域问题””的相关内容,希望看官们能喜欢,各位老铁们快快来学习一下吧!

JS必知必会: 作用域 | 上下文 this | 闭包

添加图片注释,不超过 140 字(可选)

目标作用域、函数提升、变量提升、块级作用域、作用域链、变量查找规则、IFFE的概念及使用上下文 this闭包知识要点作用域

作用域(scope)就是变量的可访问范围,即作用域控制变量的可见性和生命周期

作用域链

添加图片注释,不超过 140 字(可选)

多层包裹 | 多层调用

let a = 'global'console.log(a) function course(){  let b = 'zhaowa'  console.log(b)  session()  function session(){    let c = 'this'    console.log(c)    teacher()    function teacher(){     	let d = 'yy'      console.log(d)      console.log('test1', b)    }  }}course()

为什么函数调用和函数定义顺序可以颠倒? 函数提升 Hoist, 不用关注函数在哪里声明。变量会存在提升么? 变量提升 var -> 变量声明提升 var b = undefined内部可以取到外部的变量, 外部不能取到内部。作用域是向上查找的,冒泡查询。作用域查找 -> 函数提升 -> 变量提升 -> let 和 const 具有块级作用域, 实现隔离 -> 模块化(基础是函数)IFFE 立即执行函数,可以用来实现作用域隔离

this 上下文 context 在JavaScript中,上下文(context)通常指的是函数执行时的环境,这包括函数内部的变量,this的值,以及其他与特定函数调用相关的值。当函数被调用时,会创建一个上下文,这个上下文定义了函数内部代码可以访问的变量,函数参数,以及this的值。

this 是在执行时动态读取上下文决定的, 而不是创建时。作用域链和上下文有什么区别? 对于编译器来说, 作用域链是创建态(静态分析), 上下文是执行态(执行的时候确定)各个使用态中的指针指向:

函数中直接调用-this指向执行全局

function foo(){  console.log("函数内部this", this)}foo(); // 指向全局的 windowconst foo2 = function(){ console.log(this)}foo2() // => window;(function () {  console.log(this)})() // => window

隐式绑定

function fn(){  console.log("隐式绑定", this)}const obj = {  a: 1,  fn}obj.fn = fnobj.fn() // => obj  谁调用fn, this 就是谁。const foo = {  bar: 10,  fn: function(){    console.log(this.bar)    console.log(this)  }}let fn1 = foo.fnfn1() // undefined , window// 问题: 如何改变属性的指向? 三种方式const o1 = {  text: 'o1',  fn: function(){    console.log(this)    return this.text  }}const o2 = {  text: 'o2',  fn: function(){    console.log(this)    return o1.fn()  }}const o3 = {  text: 'o3',  fn: function(){    console.log(this)    let fn = o1.fn    return fn()  }}console.log(o1.fn());// 'o1'console.log(o2.fn());// 'o1'console.log(o3.fn());// undefined   o3.fn() => 全局执行 fn() => window

显示绑定- bind & call & apply call & apply & bind 的区别 相同点: 认为的改变this的指向 不同点:

call 和 apply 传参不同, call 上下文和参数列表 , apply 上下文和数组参数bind 返回一个函数, call 和 apply 立即执行,返回结果

手写一个bind

// 1. 说明原理, 写下注释// 2. 根据注释补全代码// 需求: 手写 bind// bind 挂载位置 => 方法 => Function.prototype// 输入: arguments 第一项是 this (上下文), 第二项到最后一项为函数的传参// 返回值: 函数, 内部构造一个函数 => 返回原函数的结果且传参继承Function.prototype.newBind = function () {  //  当前执行态的 this  const _this = this  // 伪数组 [Arguments] { '0': {}, '1': 1, '2': 2, '3': 3 }  console.log(`arguments`, arguments)  // 将伪数组转为数组  const args = Array.prototype.slice.call(arguments)  // const args = Array.from(arguments) // 另一种转换方法  console.log(args)  const context = args.shift() // 将栈顶(context) 推出  return function () {    return _this.newApply(context, args)  }}Function.prototype.newApply = function (context, args = []) {  // 边缘检测  if (typeof this !== 'function') {    throw new TypeError('TYPE ERROR')  }  context = context || window  const key = Symbol()  context[key] = this  let result = context[key](...args) // foo 会在这里执行  delete context[key] // [Symbol()] 销毁  return result}function foo() {  console.log(this) // { name: 'my', [Symbol()]: [Function: foo] }  console.log(`foo`, Array.from(arguments))}foo.newBind({ name: 'my' }, 1, 2, 3, 4)()

闭包 任何帮助局部变量逃逸到外部的方式就可以称为是闭包。 补充知识点 什么是伪数组(类数组)? 伪数组如何转成数组。 指类似数组的对象,但是并不具备数组的方法。 常见的伪数组包括函数的 arguments 对象、DOM 元素集合(比如 document.getElementsByTagName() 返回的对象)、以及通过一些内置方法(比如 querySelectorAll)获取到的元素集合等。 伪数组转换为真正的数组有三种方法 1. Array.from 2. 展开运算符 [...pseudoArray] 3. Array.prototype.slice.call() 因为 slice() 方法是数组对象的一个方法,它会创建一个新的数组对象,并将原始数组(或者类数组对象)的一部分元素复制到新数组中。当您调用 slice() 方法时,JavaScript 引擎会检查调用该方法的对象是否是一个数组。如果调用该方法的对象不是数组,JavaScript 引擎会尝试将其转换为一个数组。而且,它会检查对象是否具有 length 属性,以确定要复制的元素数量。

标签: #js块级作用域问题