js + 函数/变量提升 + 作用域 + 上下文 + this 应用

文章目录

    • js 基础应用(变量/函数/作用域)
    • 函数提升与变量提升的差异
    • this 应用
    • js 中的上下文
    • 作用域 参数 共享

js 基础应用(变量/函数/作用域)

  1. 变量声明提升实例

    • 在JavaScript中,变量声明会被提升到当前作用域的顶部。例如:
    console.log(a); // 输出:undefined
    var a = 10;
    
    • 解释:虽然变量a的赋值语句在console.log之后,但是变量声明var a会被提升到作用域的顶部。在代码执行之前,JavaScript引擎会先处理变量声明。此时a已经被声明,但是还没有赋值,所以输出undefined
  2. 函数提升实例

    • 函数声明也会被提升。例如:
    sayHello(); // 输出:Hello!
    function sayHello() {console.log("Hello!");
    }
    
    • 解释:函数sayHello的声明被提升到了当前作用域的顶部,所以在调用它之前,JavaScript引擎已经知道了这个函数的存在,因此可以正常调用。
    • 注意,如果是函数表达式,情况会有所不同:
    sayHi(); // 报错:Uncaught TypeError: sayHi is not a function
    var sayHi = function() {console.log("Hi!");
    };
    
    • 解释:这里var sayHi这个变量声明被提升了,但是赋值(也就是函数表达式部分)没有被提升。所以在调用sayHi的时候,它的值是undefined,并不是一个函数,从而导致报错。
  3. 作用域实例应用

    • 全局作用域和局部作用域
      • 全局作用域:
        var globalVar = 100;
        function globalFunction() {console.log(globalVar);
        }
        globalFunction(); // 输出:100
        
        • 解释:变量globalVar在全局作用域中声明,函数globalFunction也在全局作用域中定义。函数globalFunction可以访问全局变量globalVar
      • 局部作用域:
        function outerFunction() {var outerVar = 200;function innerFunction() {console.log(outerVar);}innerFunction(); // 输出:200
        }
        outerFunction();
        
        • 解释:outerFunction创建了一个局部作用域,变量outerVar在这个局部作用域中声明。innerFunctionouterFunction的内部,它可以访问outerFunction作用域中的变量outerVar,这是因为JavaScript的词法作用域规则,内部函数可以访问其外部函数的变量。
    • 块级作用域(ES6中的letconst
      • 例如:
        {let blockVar = 300;console.log(blockVar); // 输出:300
        }
        console.log(blockVar); 
        // 报错:Uncaught ReferenceError: blockVar is not a defined
        
        • 解释:使用let声明的变量具有块级作用域。在这个例子中,变量blockVar只在花括号{}内部的块级作用域中有效。在块级作用域外部访问它会导致报错。const也有类似的块级作用域特性,并且const声明的变量一旦赋值就不能重新赋值(对于基本数据类型)。例如:
        const PI = 3.14;
        // PI = 3.14159;// 报错:Uncaught TypeError: Assignment to constant variable.
        

函数提升与变量提升的差异

  1. 提升机制的本质差异
    • 变量提升
      • 对于使用var关键字声明的变量,JavaScript引擎会在执行代码之前,将变量声明提升到当前作用域的顶部。但变量的初始化不会被提升。例如:
      console.log(a); // 输出:undefined
      var a = 10;
      
      • 在这里,变量a的声明被提升了,所以在console.log语句执行时,JavaScript知道有变量a这个标识符,但是此时a还没有被赋值,所以它的值是undefined
    • 函数提升
      • 函数声明会被整个提升到当前作用域的顶部。这意味着函数的定义在代码执行之前就已经被处理好了,包括函数体内部的逻辑。例如:
      sayHello(); // 输出:Hello!
      function sayHello() {console.log("Hello!");
      }
      
      • 函数sayHello的整个定义被提升,所以在调用它之前,JavaScript引擎就已经知道这个函数的存在,并且可以正确地执行函数内部的代码。
  2. 提升后的行为差异
    • 变量提升后访问行为
      • 变量提升后,如果在变量初始化之前访问它,会得到undefined。而且如果在一个作用域内重复使用var声明同一个变量,JavaScript会忽略后面的声明,例如:
      var a = 10;
      var a;
      console.log(a); // 输出:10
      
      • 这是因为变量声明被提升后,后面的var a声明就相当于被忽略了,变量a的值还是最初赋值的10
    • 函数提升后访问行为
      • 函数提升后,可以在函数声明之前调用函数。而且如果在同一个作用域内重复定义同名函数,后面的函数定义会覆盖前面的函数定义。例如:
      function add(a, b) {return a + b;
      }
      function add(a, b) {return a * b;
      }
      console.log(add(2, 3)); // 输出:6
      
      • 这里后面定义的add函数覆盖了前面的add函数,所以调用add函数时,执行的是后面的乘法运算逻辑。
  3. 对作用域的影响差异
    • 变量提升对作用域的影响
      • 变量提升是基于当前作用域的。在全局作用域中声明的变量可以在全局范围内访问,在函数作用域中声明的变量只能在函数内部访问(不考虑闭包等特殊情况)。例如:
      var globalVar = 100;
      function testFunction() {var localVar = 200;console.log(globalVar); // 输出:100console.log(localVar); // 输出:200
      }
      testFunction();
      console.log(globalVar); // 输出:100
      console.log(localVar); // 报错:Uncaught ReferenceError: localVar is not defined
      
      • 变量globalVar在全局作用域声明,localVar在函数testFunction的局部作用域声明,它们的访问受到作用域的限制。
    • 函数提升对作用域的影响
      • 函数提升同样基于作用域。函数内部可以访问外部作用域的变量,但是外部作用域通常不能直接访问函数内部的变量(除非通过返回值等方式)。例如:
      var globalVar = 100;
      function outerFunction() {var outerVar = 200;function innerFunction() {console.log(outerVar); // 输出:200console.log(globalVar); // 输出:100}innerFunction();
      }
      outerFunction();
      
      • 函数innerFunction可以访问其外部函数outerFunction中的变量outerVar以及全局变量globalVar,体现了函数提升后的作用域访问规则。

this 应用

  1. 全局应用中的this
    • 在全局环境下(浏览器中的window对象或者Node.js中的global对象),this通常指向全局对象。
    • 例如在浏览器环境中:
    console.log(this === window); // true
    var globalVariable = 10;
    this.globalVariable; // 可以通过this访问全局变量,等同于window.globalVariable
    function globalFunction() {console.log(this); // 这里的this指向window
    }
    globalFunction();
    
    • 解释:在全局函数内部,this同样指向全局对象。因为全局函数实际上是作为全局对象(window)的方法来执行的。当在全局范围内定义变量时,这些变量实际上是全局对象的属性,所以可以通过this来访问。
  2. 局部函数应用中的this
    • 对象方法中的this
      • 当函数作为对象的方法被调用时,this指向该对象。例如:
      let person = {name: "Alice",sayHello: function() {console.log("Hello, my name is " + this.name);}
      };
      person.sayHello(); // 输出:Hello, my name is Alice
      
      • 解释:在sayHello方法中,this指向person对象。所以可以通过this.name访问person对象的name属性。
    • 事件处理函数中的this
      • 在HTML事件处理函数中(在浏览器环境下),this通常指向触发事件的元素。例如:
      <button onclick="console.log(this.textContent)">Click me</button>
      
      • 解释:当按钮被点击时,this指向按钮元素本身,this.textContent可以获取按钮上显示的文本内容。
    • 构造函数中的this
      • 在构造函数中,this指向新创建的对象实例。例如:
      function Person(name) {this.name = name;this.sayHello = function() {console.log("Hello, my name is " + this.name);};
      }
      let person1 = new Person("Bob");
      person1.sayHello(); // 输出:Hello, my name is Bob
      
      • 解释:当使用new关键字调用Person构造函数时,this在构造函数内部指向新创建的person1对象。通过this.name为对象添加属性,并且this.sayHello为对象添加方法。
  3. 调用this的方法
    • 作为对象方法调用
      • 如前面提到的person.sayHello()这种方式,通过对象来调用方法,this就会指向该对象。
    • 使用callapply方法
      • call方法:可以用来调用一个函数,并且指定函数内部this的指向,同时传递参数。例如:
      function greet(greeting) {console.log(greeting + ", " + this.name);
      }
      let person = {name: "Charlie"};
      greet.call(person, "Hi"); // 输出:Hi, Charlie
      
      • 解释:call方法的第一个参数是要绑定this的对象,后面的参数是函数greet需要的参数。在这里,thisgreet函数内部就指向了person对象。
      • apply方法:和call类似,但是传递参数的方式不同。apply接收两个参数,第一个是要绑定this的对象,第二个是一个包含函数参数的数组。例如:
      function addNumbers(a, b) {return this.sum + a + b;
      }
      let calculator = {sum: 10};
      let args = [2, 3];
      addNumbers.apply(calculator, args); // 输出:15
      
    • 使用bind方法
      • bind方法会创建一个新的函数,新函数内部的this会永久地绑定到指定的对象上。例如:
      function multiply(a, b) {console.log(this.value * a * b);
      }
      let multiplier = {value: 2};
      let boundMultiply = multiply.bind(multiplier);
      boundMultiply(3, 4); // 输出:24
      
      • 解释:bind方法返回一个新的函数boundMultiply,这个新函数内部的this永远指向multiplier对象。即使将boundMultiply作为其他对象的方法调用或者在其他作用域中调用,this的指向也不会改变。
  4. 改变this指向的方法总结
    • 主要有三种方式:callapplybind。它们的区别在于参数传递方式和是否立即执行函数。callapply会立即执行函数,而bind返回一个新的函数,需要再次调用这个新函数才会执行。这些方法在处理面向对象编程、函数复用以及事件处理等场景中非常有用,可以灵活地控制this的指向,以满足不同的业务需求。

js 中的上下文

  1. 全局上下文(Global Context)

    • 定义
      • 全局上下文是JavaScript代码执行的最外层环境。在浏览器环境中,全局上下文对应的对象是window,在Node.js环境中是global。它包含了所有全局变量和函数,这些变量和函数可以在代码的任何位置访问(除非被函数作用域或块级作用域隐藏)。
    • 实例
      • 在浏览器环境下,我们可以这样理解全局上下文:
      var globalVariable = 10;
      function globalFunction() {console.log("This is a global function");
      }
      console.log(window.globalVariable);// 输出:10,说明globalVariable是window对象的属性
      console.log(window.globalFunction);// 输出:function globalFunction() {...},说明globalFunction是window对象的属性
      
      • 解释:这里的globalVariableglobalFunction都是在全局上下文中定义的,它们实际上是window对象的属性和方法。当我们在浏览器中访问window对象时,可以看到这些定义的变量和函数。
      • 在Node.js环境下:
      global.sharedVariable = 20;
      function sharedFunction() {console.log("This is a global function in Node.js");
      }
      console.log(global.sharedVariable); // 输出:20
      console.log(global.sharedFunction); // 输出:function sharedFunction() {...}
      
      • 解释:在Node.js中,全局对象是global,和浏览器中的window类似,全局变量和函数是作为global对象的属性和方法存在的。
  2. 作用域上下文(Scope Context)

    • 定义
      • 作用域上下文决定了变量和函数的可访问性和生命周期。JavaScript有函数作用域和块级作用域。函数作用域是指在函数内部定义的变量只能在函数内部访问,块级作用域(通过letconst声明变量)是指在{}大括号内定义的变量只能在这个块内访问。
    • 函数作用域实例
      • 例如:
      function outerFunction() {var outerVariable = 30;function innerFunction() {console.log(outerVariable); // 输出:30,可以访问outerVariable}innerFunction();
      }
      outerFunction();
      console.log(outerVariable); 
      // 报错:Uncaught ReferenceError: outerVariable is not defined,无法在函数外部访问outerVariable
      
      • 解释:outerVariable是在outerFunction的函数作用域内定义的,innerFunction可以访问outerVariable是因为JavaScript的词法作用域规则,内部函数可以访问其外部函数定义的变量。但是在outerFunction外部,outerVariable是不可访问的。
    • 块级作用域实例
      {let blockVariable = 40;console.log(blockVariable); // 输出:40
      }
      console.log(blockVariable); 
      // 报错:Uncaught ReferenceError: blockVariable is not defined,无法在块外部访问blockVariable
      
      • 解释:这里使用let声明了blockVariable,它具有块级作用域,只能在{}这个块内部被访问。当代码执行到块外部时,变量blockVariable就不再可访问了。

作用域 参数 共享

  1. 通过返回值共享变量(函数作用域)

    • 原理
      • 在函数内部定义的变量,默认情况下其作用域仅限于函数内部。但是可以通过将变量作为函数的返回值,使得外部代码能够访问函数内部的变量。
    • 示例
      function createCounter() {let count = 0;return function() {count++;return count;};
      }
      let counter = createCounter();
      console.log(counter()); // 输出:1
      console.log(counter()); // 输出:2
      
      • 解释:createCounter函数内部定义了变量count,它的初始值为0。然后createCounter返回一个内部函数,这个内部函数可以访问count变量。当我们调用counter(也就是createCounter返回的内部函数)时,count变量的值会递增并返回。这样就通过返回值的方式,让外部代码能够访问和修改函数内部定义的变量。
  2. 全局变量共享(全局作用域与函数作用域交互)

    • 原理
      • 全局变量可以在函数内部访问和修改,从而实现作用域之间的交互。不过,过度使用全局变量可能会导致代码的可维护性变差。
    • 示例
      let globalVariable = 10;
      function modifyGlobalVariable() {globalVariable += 5;console.log(globalVariable); // 输出:15
      }
      modifyGlobalVariable();
      console.log(globalVariable); // 输出:15
      
      • 解释:在这个例子中,globalVariable是一个全局变量。modifyGlobalVariable函数可以访问并修改这个全局变量。在函数内部修改globalVariable后,其值在函数外部也会发生改变,因为它们引用的是同一个变量。
  3. 闭包共享变量(函数作用域与外部作用域)

    • 原理
      • 闭包是指有权访问另一个函数内部变量的函数。一个函数返回了另一个函数,并且这个返回的函数引用了外部函数的局部变量,就形成了闭包。通过闭包可以在不同的函数调用之间保持变量的状态,并且可以从外部访问内部变量。
    • 示例
      function outerFunction() {let privateVariable = 20;function innerFunction() {console.log(privateVariable);}return innerFunction;
      }
      let closureFunction = outerFunction();
      closureFunction(); // 输出:20
      
      • 解释:outerFunction返回innerFunctioninnerFunction可以访问outerFunction内部的privateVariable,形成了闭包。当我们调用closureFunction(也就是innerFunction)时,它能够访问privateVariable,即使outerFunction已经执行完毕。这样就实现了从外部访问函数内部变量的效果,并且通过闭包可以在不同的时间点访问和操作这些变量。
  4. 通过对象属性共享(函数作用域与对象作用域)

    • 原理
      • 可以将函数内部的变量作为对象的属性,通过返回对象或者修改对象属性的方式,让外部代码能够访问这些变量。
    • 示例
      function createObjectWithVariable() {let internalVariable = 30;return {getVariable: function() {return internalVariable;},setVariable: function(newValue) {internalVariable = newValue;}};
      }
      let objectWithVariable = createObjectWithVariable();
      console.log(objectWithVariable.getVariable()); // 输出:30
      objectWithVariable.setVariable(40);
      console.log(objectWithVariable.getVariable()); // 输出:40
      
      • 解释:createObjectWithVariable函数内部定义了internalVariable,然后返回一个对象,这个对象有两个方法getVariablesetVariablegetVariable方法可以获取internalVariable的值,setVariable方法可以修改它的值。通过这种方式,外部代码可以通过对象的方法来访问和修改函数内部的变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/10435.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

斯坦福泡茶机器人DexCap源码解析:涵盖收集数据、处理数据、模型训练三大阶段

前言 因为我司「七月在线」关于dexcap的复现/优化接近尾声了&#xff0c;故准备把dexcap的源码也分析下。​下周则分析下iDP3的源码——为队伍「iDP3人形的复现/优化」助力 最开始&#xff0c;dexcap的源码分析属于此文《DexCap——斯坦福李飞飞团队泡茶机器人&#xff1a;带…

高中数学:概率-随机实验、样本空间、随机事件

文章目录 一、随机实验二、样本空间三、随机事件例题 四、事件运算 一、随机实验 二、样本空间 三、随机事件 例如 样本空间 Ω { a , b , c , d , e , f } 则&#xff0c;事件 A { a , b , c } &#xff0c;是一个随机事件 事件 B { d } 是一个基本事件 样本空间Ω\{a,b,c…

w~大模型~合集21

我自己的原文哦~ https://blog.51cto.com/whaosoft/12459590 #大模型~微调~用带反馈的自训练 面对当前微调大模型主要依赖人类生成数据的普遍做法&#xff0c;谷歌 DeepMind 探索出了一种减少这种依赖的更高效方法。大模型微调非得依赖人类数据吗&#xff1f;用带反馈的自训…

利用 Vue.js 开发动态组件的实战指南

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; Vue.js 是现代 Web 开发中非常流行的框架&#xff0c;以其渐进式架构和组件化设计受到广泛欢迎。组件化开发是 Vue.js 的核心优势…

Jmeter中的配置原件(一)

配置原件 1--CSV Data Set Config 用途 参数化测试&#xff1a;从CSV文件中读取数据&#xff0c;为每个请求提供不同的参数值。数据驱动测试&#xff1a;使用外部数据文件来驱动测试&#xff0c;使测试更加灵活和可扩展。 配置步骤 准备CSV文件 创建一个CSV文件&#xff0c…

MCU的OTA升级(未完-持续更新)

1.术语 ISP : In-System Programming 在系统编程&#xff0c;是一种通过MCU&#xff08;微控制器单元&#xff09;上的内置引导程序&#xff08;BootLoader&#xff09;来实现对芯片内部存储器&#xff08;如Flash&#xff09;进行编程的技术。 华大目前对应的ISP IAP&…

让redis一直开启服务/自动启动

文章目录 你的redis是怎么打开的黑窗不能关?必须要自动启动吗?再说说mysql 本文的所有指令都建议在管理员权限下打开cmd控制台 推荐的以管理员身份打开控制台的方式 Win R 打开运行 输入cmdShift Ctrl Enter 你的redis是怎么打开的 安装过redis的朋友都知道, redis的安…

从认识 VNode VDOM 到实现 mini-vue

前言 现有框架几乎都引入了虚拟 DOM 来对真实 DOM 进行抽象&#xff0c;也就是现在大家所熟知的 VNode 和 VDOM&#xff0c;那么为什么需要引入虚拟 DOM 呢&#xff1f;下面就一起来了解下吧&#xff01;&#xff01;&#xff01; VNode & VDOM VNode 和 VDOM 是什么&am…

vue项目实战

1.项目文件夹添加&#xff08;结构如下&#xff09; 2.页面构建 安装路由 npm install react-router-dom 3.页面基本模板 router文件夹下index.js的模板 // 引入组件 import Login from "../views/login"; // 注册路由数组 const routes [{// 首页默认是/path: …

SD-WAN跨境加速专线:打造无缝、高效的全球社交媒体营销网络

在数字化时代&#xff0c;电子商务与社交媒体的融合已成为不可逆转的趋势。亚马逊&#xff0c;作为全球领先的电子商务平台&#xff0c;近期与Facebook、Instagram、Snapchat、Pinterest和TikTok等社交媒体巨头携手&#xff0c;推出了一项革命性的无缝购物体验。这一创新举措不…

yelp商家数据集上使用火算法求解TSP 问题

先简要回顾下什么是TSP问题&#xff0c; 旅行商问题&#xff08;Traveling Salesman Problem&#xff0c;TSP&#xff09;是一个经典的组合优化问题&#xff0c;广泛应用于运筹学、计算机科学和物流等领域。TSP的基本描述如下&#xff1a; 问题描述 定义&#xff1a;假设有一…

【深度学习目标检测|YOLO算法1】YOLO家族进化史:从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析...

【深度学习目标检测|YOLO算法1】YOLO家族进化史&#xff1a;从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析… 【深度学习目标检测|YOLO算法1】YOLO家族进化史&#xff1a;从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析… 文章目录 【深度学习目标检测|YOL…

星期-时间范围选择器 滑动选择时间 最小粒度 vue3

星期-时间范围选择器 功能介绍属性说明事件说明实现代码使用范例 根据业务需要&#xff0c;实现了一个可选择时间范围的周视图。用户可以通过鼠标拖动来选择时间段&#xff0c;并且可以通过快速选择组件来快速选择特定的时间范围。 功能介绍 时间范围选择&#xff1a;用户可以…

Java | Leetcode Java题解之第554题砖墙

题目&#xff1a; 题解&#xff1a; class Solution {public int leastBricks(List<List<Integer>> wall) {Map<Integer, Integer> cnt new HashMap<Integer, Integer>();for (List<Integer> widths : wall) {int n widths.size();int sum 0…

牛客小白月赛104 —— C.小红打怪

C.小红打怪 1.题目&#xff1a; 2.样例 输入 5 1 2 3 4 5 输出 2 说明 第一回合&#xff0c;小红攻击全体怪物&#xff0c;队友1攻击5号怪物&#xff0c;队友2攻击4号和5号怪物&#xff0c;剩余每只怪物血量为[0,1,2,2,2]。 第二回合&#xff0c;小红攻击全体怪物&#…

python画图|text()和dict()初探

【1】引言 在进行hist()函数的学习进程中&#xff0c;了解到了subplot_mosaic()函数&#xff0c;在学习subplot_mosaic()函数的时候&#xff0c;又发现了text()和dict()函数。 经探究&#xff0c;text()和dict()函数有很多一起使用的场景&#xff0c;为此&#xff0c;我们就一…

BUG: scheduling while atomic

▌▌上篇文章的内容还没有结束 中断处理函数中如果执行了调度&#xff0c;会发生什么 ▌这次&#xff0c;我修改了程序&#xff0c;在中断处理函数中调用了msleep 程序执行后&#xff0c;会有这样的日志 ▌关键就是这句 BUG: scheduling while atomic 我们追代码&#xff0c;可…

算法 -选择排序

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【算法】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 文章目录 &#x1f4a1;选择排序1. &#x1f504; 选择排序&#x1f5bc;️示意图&#x1f4d6;简介&#x1f4a1;实现思路1&#x1f4bb;代码实现1&#x1f4a1;实现思路2…

ubuntu 22.04 镜像源更换

双11抢了个云服务器&#xff0c;想要整点东西玩玩&#xff0c;没想到刚上来就不太顺利 使用sudo apt update更新软件&#xff0c;然后发生了如下报错 W: Failed to fetch http://mirrors.jdcloudcs.com/ubuntu/dists/jammy/InRelease 理所当然想到可能是镜像源连接不是很好&…

2016年7月29日至2017年2月21日NASA大气层层析(ATom)任务甲醛(HCHO)、羟基(OH)和OH生产率的剖面积分柱密度

目录 简介 摘要 引用 网址推荐 知识星球 机器学习 ATom: Column-Integrated Densities of Hydroxyl and Formaldehyde in Remote Troposphere ATom&#xff1a; 远对流层中羟基和甲醛的柱积分密度 简介 该数据集提供了甲醛&#xff08;HCHO&#xff09;、羟基&#xff…