news 2026/2/5 4:25:54

JavaScript 里的词法环境(Lexical Environment)与变量环境(Variable Environment)的区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 里的词法环境(Lexical Environment)与变量环境(Variable Environment)的区别

各位同学,大家下午好!

今天,我们将深入探讨 JavaScript 中两个核心但常常被混淆的概念:词法环境(Lexical Environment)与变量环境(Variable Environment)。理解它们之间的区别和联系,是掌握 JavaScript 作用域、变量生命周期以及闭包等高级特性的基石。作为一名编程专家,我希望通过这次讲座,能够彻底厘清这两个概念,并帮助大家构建一个更坚实的 JavaScript 知识体系。

我们将从宏观的执行上下文(Execution Context)开始,逐步解构其内部的运行机制,最终聚焦到词法环境和变量环境的具体作用及其动态变化。请大家准备好,让我们一起踏上这段探索之旅。

一、宏观视角:执行上下文(Execution Context)

在 JavaScript 代码执行的任何时刻,它都运行在一个特定的“环境”中,这个环境就是执行上下文(Execution Context)。执行上下文是 JavaScript 引擎用来管理代码执行流程、变量存储和函数调用的核心机制。每当 JavaScript 引擎准备执行一段代码时(无论是全局代码、函数代码还是eval代码),它都会创建一个新的执行上下文。

一个执行上下文在逻辑上包含三个主要部分:

  1. 变量环境(Variable Environment):我们今天的重点之一。它是一个特殊的词法环境,用于存储当前上下文中的变量(特别是var声明的变量)和函数声明。
  2. 词法环境(Lexical Environment):今天的另一个重点。它是一个抽象概念,用于定义标识符(变量名、函数名)到特定变量或函数的映射关系。它在执行过程中可以动态变化。
  3. this绑定(thisBinding):确定当前执行上下文中this关键字的值。

我们今天的讨论将主要围绕前两个组件展开。

JavaScript 引擎在创建执行上下文时,会经历两个阶段:

  1. 创建阶段(Creation Phase)
    • 确定this的值。
    • 创建词法环境组件。
    • 创建变量环境组件。
    • (重要)处理函数声明和var变量声明,将它们添加到变量环境(并因此也添加到词法环境)。letconst变量在此阶段也会被处理,但不会被初始化,并被放置在“暂时性死区”(Temporal Dead Zone, TDZ)中,直到它们被实际声明的代码行执行。
  2. 执行阶段(Execution Phase)
    • 逐行执行代码,对变量进行赋值,并执行函数调用。

理解这两个阶段对于我们后续区分词法环境和变量环境至关重要。

二、深入剖析:词法环境(Lexical Environment)

词法环境是 JavaScript 规范中定义的一种抽象数据结构,它用于存储标识符和它们所绑定的变量/函数的关联关系。它是一个核心概念,决定了 JavaScript 中变量和函数的可访问性,也就是我们常说的“作用域”。

什么是“词法”?

“词法”一词指的是代码的物理结构,即在代码被写下和编译(或解析)时,变量和函数在代码中的位置。一个函数的作用域在它被定义时就确定了,而不是在它被调用时。这是 JavaScript 作用域链的基础。

2.1 词法环境的结构

每个词法环境都包含两个主要组件:

  1. 环境记录器(Environment Record)
    • 这是一个实际存储标识符绑定(即变量名与值的映射)的地方。
    • 它可以是以下两种类型之一:
      • 声明式环境记录器(Declarative Environment Record):用于存储函数声明、变量声明(var,let,const)以及catch块中的变量。它直接将标识符映射到它们的值。
      • 对象环境记录器(Object Environment Record):主要用于全局上下文。它将标识符绑定到指定的对象属性上。例如,在全局上下文中,var声明的变量和函数声明都会成为全局对象(浏览器中是window,Node.js 中是global)的属性。with语句也会创建对象环境记录器。
  2. 外部词法环境引用(Outer Lexical Environment Reference)
    • 这是一个指向其父级(即包含它的)词法环境的引用。
    • 这个引用是构建作用域链的关键。当 JavaScript 引擎需要查找一个变量时,它会首先在当前的词法环境的环境记录器中查找。如果找不到,它就会沿着Outer Lexical Environment Reference向上查找,直到找到该变量或者到达全局词法环境(如果仍未找到,则抛出ReferenceError)。

2.2 词法环境的创建与作用域链

每当:

  • 全局代码执行时。
  • 一个函数被调用时。
  • 一个letconst声明的块级作用域被进入时。
  • with语句或catch块被执行时。

都会创建一个新的词法环境。

让我们通过一个简单的例子来理解词法环境及其外部引用:

var globalVar = "我是全局变量"; function outerFunction() { var outerVar = "我是外部函数变量"; function innerFunction() { var innerVar = "我是内部函数变量"; console.log(innerVar); // 查找 innerVar console.log(outerVar); // 查找 outerVar console.log(globalVar); // 查找 globalVar } innerFunction(); } outerFunction();

innerFunction被调用时:

  1. innerFunction的词法环境被创建。
    • 其环境记录器包含innerVar
    • Outer Lexical Environment Reference指向outerFunction的词法环境
  2. console.log(innerVar)执行时,引擎在innerFunction的环境记录器中找到innerVar
  3. console.log(outerVar)执行时,引擎在innerFunction的环境记录器中找不到outerVar。它会沿着Outer Lexical Environment Reference向上,进入outerFunction的词法环境。
  4. outerFunction的环境记录器中找到outerVar
  5. console.log(globalVar)执行时,引擎在innerFunctionouterFunction的环境记录器中都找不到globalVar。它会继续沿着Outer Lexical Environment Reference向上,进入全局词法环境
  6. 在全局词法环境的环境记录器中找到globalVar

这个查找过程就是作用域链(Scope Chain)。词法环境的Outer Lexical Environment Reference构成了这个链条。

2.3 闭包与词法环境

词法环境是理解闭包(Closure)的关键。闭包是指一个函数能够记住并访问其词法作用域,即使该函数在其词法作用域之外执行。

function makeCounter() { let count = 0; // count 存在于 makeCounter 的词法环境的环境记录器中 return function() { // 这个匿名函数 count++; console.log(count); }; } const counter1 = makeCounter(); counter1(); // 1 counter1(); // 2 const counter2 = makeCounter(); // 再次调用 makeCounter 会创建新的词法环境 counter2(); // 1

makeCounter被调用时,它创建了一个新的词法环境,其中包含count变量。它返回的匿名函数在创建时,其Outer Lexical Environment Reference就被设置为指向这个makeCounter的词法环境。

即使makeCounter执行完毕,其词法环境通常会被销毁,但由于返回的匿名函数仍然持有对它的引用(通过Outer Lexical Environment Reference),这个词法环境就不会被垃圾回收,count变量也得以保留。这就是闭包的魔力。

2.4 块级作用域与词法环境

ES6 引入了letconst,它们支持块级作用域。这意味着{}括号内的代码块也会创建新的词法环境。

function blockScopeExample() { var x = 10; let y = 20; if (true) { var x = 30; // 这里的 x 还是指向函数作用域的 x let y = 40; // 这里的 y 是一个新的块级作用域变量 const z = 50; console.log("Inside block:"); console.log("x:", x); // 30 console.log("y:", y); // 40 console.log("z:", z); // 50 } console.log("Outside block:"); console.log("x:", x); // 30 (var 的副作用) console.log("y:", y); // 20 (let 的块级作用域特性) // console.log("z:", z); // ReferenceError: z is not defined } blockScopeExample();

在这个例子中:

  1. blockScopeExample函数执行时,它会创建一个函数词法环境。
    • 这个环境的环境记录器中包含x(初始值 10) 和y(初始值 20)。
  2. 当进入if (true)块时,JavaScript 引擎会为这个块创建一个新的词法环境
    • 这个新的词法环境的Outer Lexical Environment Reference指向blockScopeExample的词法环境。
    • 这个新环境的环境记录器中包含块级y(初始值 40) 和z(初始值 50)。
    • var x = 30并没有在这个块级词法环境中创建新的绑定,而是修改了blockScopeExample词法环境中的x。这是var的一个重要特性:它没有块级作用域。
  3. if块结束时,其对应的词法环境会被销毁(如果不再有引用)。

这清晰地展示了let/const如何通过创建新的词法环境来实现块级作用域。

三、深入剖析:变量环境(Variable Environment)

现在,让我们把焦点转向变量环境。变量环境是执行上下文的一个组件,它是一个特殊的词法环境。

更准确地说,变量环境是执行上下文的词法环境在创建阶段的快照。它包含了在该执行上下文中通过var关键字声明的变量和函数声明。这些声明在创建阶段就会被处理,并添加到变量环境的环境记录器中,无论它们在代码中的物理位置如何(这就是var和函数声明的“提升”现象)。

3.1 变量环境的核心特性

  1. 在创建阶段被设置:当一个执行上下文被创建时,它的变量环境就会被初始化。所有var声明的变量和函数声明都会被添加到这个环境记录器中。
  2. 包含var和函数声明:这是它与普通词法环境在行为上最主要的区别。
  3. 不处理letconstletconst声明的变量不会被添加到变量环境。它们会在其各自的块级词法环境中进行管理。
  4. 通常保持不变:一旦变量环境在执行上下文的创建阶段被建立,它在整个执行上下文的生命周期内通常是不会改变的。而执行上下文的当前词法环境(LexicalEnvironment属性) 可以在执行阶段动态地被更新,以反映进入和退出块级作用域的情况。

3.2 变量环境与提升(Hoisting)

变量环境是解释var和函数声明提升现象的根本。

function hoistingExample() { console.log(a); // undefined var a = 10; console.log(a); // 10 console.log(b); // ReferenceError: b is not defined (TDZ) let b = 20; foo(); // "Hello from foo!" function foo() { console.log("Hello from foo!"); } bar(); // TypeError: bar is not a function (bar is hoisted but undefined) var bar = function() { console.log("Hello from bar!"); }; } hoistingExample();

hoistingExample函数的执行上下文创建时:

  1. 变量环境被创建。
  2. var a被扫描到,a被添加到变量环境的环境记录器中,并初始化为undefined
  3. function foo()被扫描到,foo被添加到变量环境的环境记录器中,并直接绑定到函数定义。
  4. var bar被扫描到,bar被添加到变量环境的环境记录器中,并初始化为undefined
  5. let b被扫描到,b也被“提升”,但它不被添加到变量环境,而是被放置在当前词法环境(函数词法环境)的“暂时性死区”(TDZ)中。

在执行阶段:

  • console.log(a):此时a已在变量环境中存在且为undefined,所以输出undefined
  • a = 10a被赋值为10
  • console.log(a):输出10
  • console.log(b):此时b仍在 TDZ 中,访问会报错ReferenceError
  • let b = 20b被初始化并赋值。
  • foo()foo已经在变量环境中完全初始化,可以正常调用。
  • bar()bar此时在变量环境中为undefined,尝试调用undefined会导致TypeError
  • var bar = function() { ... }bar被赋值为函数表达式。

这个例子清晰地展示了变量环境如何在执行上下文的创建阶段处理var和函数声明,并解释了它们的提升行为。

四、核心差异与动态演变:Lexical Environment vs Variable Environment

现在我们来到了最关键的部分:它们之间的区别与联系。

表格:词法环境(Lexical Environment)与变量环境(Variable Environment)对比

特性词法环境(Lexical Environment)变量环境(Variable Environment)
定义抽象概念,用于定义标识符到变量/函数的映射,管理作用域。执行上下文的特定组件,是一个特殊的词法环境,在创建阶段被初始化。
包含内容所有类型的声明(var,let,const,function)以及参数。仅包含var声明的变量和函数声明。
动态性在执行上下文的生命周期内,其Environment RecordOuter Lexical Environment Reference会根据代码块的进入和退出而动态变化。一旦在执行上下文的创建阶段被设置,在其整个生命周期内通常保持不变。
主要用途管理整个作用域链,决定变量查找规则,支持闭包和块级作用域。主要用于在创建阶段处理var变量和函数声明的提升。
与EC的关系执行上下文的LexicalEnvironment属性指向当前活跃的词法环境。执行上下文的VariableEnvironment属性指向创建阶段的词法环境。
let/constlet/const声明的变量会创建新的词法环境,或在现有词法环境中绑定。不包含let/const声明的变量。

4.1 初始状态:两者通常相同

在执行上下文的创建阶段,当没有遇到任何块级作用域(由letconst引起)时,执行上下文的LexicalEnvironment属性和VariableEnvironment属性通常会指向同一个词法环境对象。

// 假设这是函数执行上下文的伪代码表示 ExecutionContext = { LexicalEnvironment: <FunctionLexicalEnvironment>, VariableEnvironment: <FunctionLexicalEnvironment>, // 初始时指向同一个对象 ThisBinding: ... } FunctionLexicalEnvironment = { EnvironmentRecord: { // var 变量和函数声明被添加到这里 // 假设 var x = 10; function foo() {} x: undefined, // for var foo: <func obj> }, OuterLexicalEnvironmentReference: <ParentLexicalEnvironment> }

4.2 动态演变:当LexicalEnvironment偏离VariableEnvironment

这是理解两者区别的关键点。VariableEnvironment一旦在创建阶段被设置,就固定了。但LexicalEnvironment动态的。当 JavaScript 引擎在执行阶段遇到letconst声明的块时,它会创建一个新的词法环境,并更新执行上下文的LexicalEnvironment属性来指向这个新的词法环境。

让我们通过一个详细的例子来模拟这个过程:

function dynamicEnvExample() { var a = 10; let b = 20; console.log("Before block: a =", a, "b =", b); // a=10, b=20 if (true) { var c = 30; // var 声明 let d = 40; // let 声明 console.log("Inside block: a =", a, "b =", b, "c =", c, "d =", d); // a=10, b=20, c=30, d=40 } console.log("After block: a =", a, "b =", b, "c =", c); // a=10, b=20, c=30 // console.log("After block: d =", d); // ReferenceError: d is not defined } dynamicEnvExample();

执行流程分析:

1.dynamicEnvExample()函数被调用,创建一个新的函数执行上下文。

  • 创建阶段:

    • this绑定确定。
    • 变量环境(VariableEnvironment)被创建并初始化:
      • 它是一个词法环境对象,我们称之为FuncVE
      • FuncVE.EnvironmentRecord包含:
        • a: undefined(来自var a = 10;)
        • c: undefined(来自var c = 30;注意,var提升到函数作用域)
      • FuncVE.OuterLexicalEnvironmentReference指向全局词法环境。
    • 词法环境(LexicalEnvironment)同样被创建并初始化,此时它与VariableEnvironment指向同一个对象FuncVE
      • FuncVE.EnvironmentRecord还会处理let b = 20;b被添加到FuncVE.EnvironmentRecord,但处于 TDZ。
    • ExecutionContext看起来像这样:
      ExecutionContext = { LexicalEnvironment: FuncVE, VariableEnvironment: FuncVE, ThisBinding: ... } FuncVE = { EnvironmentRecord: { a: undefined, c: undefined, b: <TDZ> }, OuterLexicalEnvironmentReference: GlobalLE }
  • 执行阶段:

    • var a = 10;FuncVE.EnvironmentRecord.aundefined更新为10

    • let b = 20;b离开 TDZ,FuncVE.EnvironmentRecord.b更新为20

    • console.log("Before block: a =", a, "b =", b);

      • 查找a:在ExecutionContext.LexicalEnvironment(即FuncVE) 中找到a: 10
      • 查找b:在ExecutionContext.LexicalEnvironment(即FuncVE) 中找到b: 20
      • 输出a=10, b=20
    • 进入if (true)块:

      • JavaScript 引擎检测到块级作用域(因为里面有let d),创建一个新的词法环境,我们称之为BlockLE
      • BlockLE.EnvironmentRecord包含:d: <TDZ>(来自let d = 40;)
      • BlockLE.OuterLexicalEnvironmentReference指向当前的ExecutionContext.LexicalEnvironment(即FuncVE)。
      • 最关键的一步:ExecutionContext.LexicalEnvironment现在更新为BlockLE
      • 注意:ExecutionContext.VariableEnvironment仍然指向FuncVE,它没有改变!
        ExecutionContext = { LexicalEnvironment: BlockLE, // 改变了! VariableEnvironment: FuncVE, // 保持不变 ThisBinding: ... } BlockLE = { EnvironmentRecord: { d: <TDZ> }, OuterLexicalEnvironmentReference: FuncVE }
    • var c = 30;

      • var没有块级作用域。它会在当前的LexicalEnvironment(即BlockLE) 中查找c。找不到时,会沿着OuterLexicalEnvironmentReference向上,在FuncVE中找到c
      • FuncVE.EnvironmentRecord.cundefined更新为30
    • let d = 40;

      • d离开 TDZ,BlockLE.EnvironmentRecord.d更新为40
    • console.log("Inside block: a =", a, "b =", b, "c =", c, "d =", d);

      • 查找aBlockLE->FuncVE找到a: 10
      • 查找bBlockLE->FuncVE找到b: 20
      • 查找cBlockLE->FuncVE找到c: 30
      • 查找d:在BlockLE中找到d: 40
      • 输出a=10, b=20, c=30, d=40
    • 退出if (true)块:

      • BlockLE不再活跃。
      • ExecutionContext.LexicalEnvironment恢复到进入块之前的状态,重新指向FuncVE
        ExecutionContext = { LexicalEnvironment: FuncVE, // 恢复了! VariableEnvironment: FuncVE, // 依然不变 ThisBinding: ... }
    • console.log("After block: a =", a, "b =", b, "c =", c);

      • 查找a:在FuncVE中找到a: 10
      • 查找b:在FuncVE中找到b: 20
      • 查找c:在FuncVE中找到c: 30
      • 输出a=10, b=20, c=30
    • // console.log("After block: d =", d);

      • 尝试查找d:在FuncVE中找不到。沿着OuterLexicalEnvironmentReference向上,在全局词法环境中也找不到。抛出ReferenceError。这是因为d所在的BlockLE已经不再是当前的LexicalEnvironment且不再可访问。

这个详细的步骤展示了LexicalEnvironment如何在执行过程中动态地在FuncVEBlockLE之间切换,而VariableEnvironment则始终保持指向FuncVE。这正是let/const实现块级作用域的底层机制。

4.3 为什么需要两者?历史与演进

这个分离设计,尤其是LexicalEnvironment的动态性,主要是为了适应 JavaScript 语言的演进:

  • var的历史包袱var只有函数作用域或全局作用域,并且存在提升。VariableEnvironment很好地封装了这种旧有的行为。
  • ES6 的块级作用域letconst引入了块级作用域,这需要一种更细粒度的作用域管理机制。如果仅仅依靠VariableEnvironment这种“创建时快照”的结构,将无法实现块级作用域。因此,LexicalEnvironment被设计成可以动态切换,以在进入和退出块时反映新的作用域。
  • 性能与简洁性:将var/function声明的静态解析(在创建阶段)与let/const的动态块级解析分开,有助于引擎在不同阶段优化代码执行。

五、实际应用与最佳实践

理解词法环境和变量环境不仅仅是学术上的探讨,它对我们编写高质量的 JavaScript 代码具有直接的指导意义。

5.1 明确作用域边界

  • var的陷阱var声明的变量会提升到其所在函数的变量环境,导致它们在整个函数体内(甚至在声明之前)都可访问。这常常导致意料之外的行为,尤其是在循环和条件语句中。

    for (var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); // 3, 3, 3 (i 在循环结束后为 3,且所有闭包共享同一个 i) }, 100); } console.log("Final i:", i); // Final i: 3

    这里的i是在全局/函数变量环境中,每次循环都修改了同一个i

  • let/const的优势letconst声明的变量存在于它们各自的块级词法环境中。每次循环迭代都会创建一个新的块级词法环境,使得变量在每次迭代中都是独立的。

    for (let j = 0; j < 3; j++) { setTimeout(function() { console.log(j); // 0, 1, 2 (每次迭代的 j 都是独立的) }, 100); } // console.log("Final j:", j); // ReferenceError: j is not defined

    这里的j在每次循环迭代时都在一个新的块级词法环境中,因此setTimeout捕获到的是每次迭代不同的j值。

5.2 避免“暂时性死区”(TDZ)问题

letconst变量在它们的代码块顶部就被“提升”了,但它们直到声明语句被执行才会被初始化。在这之间的区域就是 TDZ。尝试在 TDZ 内访问这些变量会导致ReferenceError

function tdzExample() { // console.log(x); // ReferenceError (x 处于 TDZ) let x = 10; console.log(x); // 10 } tdzExample();

理解let/const是如何被添加到其块级词法环境中,以及它们在初始化之前的状态(TDZ),有助于避免这类错误。

5.3 更好的代码可读性与维护性

使用letconst能够使得变量的作用域更加明确,只在需要的地方可见。这减少了变量污染和意外的副作用,提高了代码的可读性和可维护性。

5.4 推荐使用letconst

鉴于letconst提供了更清晰、更可预测的作用域规则,并且避免了var带来的许多常见问题,现代 JavaScript 实践强烈推荐优先使用letconst。只有在极少数需要var的特定行为(例如在非常老的浏览器环境中)时才考虑使用它。

六、结语

今天我们深入探讨了 JavaScript 中的词法环境和变量环境。我们了解到,词法环境是一个抽象且动态的概念,它定义了变量和函数在代码中的可访问性,并构成了作用域链的基础。而变量环境则是执行上下文创建时的一个特殊词法环境,专门用于处理var声明的变量和函数声明的提升。

核心的区别在于,VariableEnvironment在执行上下文的生命周期内通常是固定的,而LexicalEnvironment则会随着代码的执行,特别是进入和退出let/const块级作用域时,动态地更新以反映当前活跃的作用域。

掌握这两个概念,能够帮助我们更深刻地理解 JavaScript 的作用域机制、变量提升、闭包的本质以及varletconst之间的行为差异。这是编写健壮、可维护和高效 JavaScript 代码的必备知识。希望通过这次讲座,大家对这两个概念有了更清晰的认识。感谢大家!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/3 7:37:22

你还在为Rust-PHP扩展报错崩溃?:3种高效解决方案立即上手

第一章&#xff1a;Rust-PHP 扩展的版本适配在构建基于 Rust 编写的 PHP 扩展时&#xff0c;版本兼容性是确保扩展稳定运行的关键因素。PHP 的内部 API 随版本迭代频繁变化&#xff0c;而 Rust 通过 php-rs 或 ext-php-rs 等绑定库与 Zend 引擎交互&#xff0c;因此必须精确匹配…

作者头像 李华
网站建设 2026/1/29 14:31:51

仅限高级开发者:PHP 8.6扩展开发文档未公开的7个核心结构体

第一章&#xff1a;PHP 8.6 扩展开发概览 PHP 8.6 作为 PHP 语言持续演进的重要版本&#xff0c;进一步优化了扩展开发的接口稳定性与性能表现。该版本在延续 Zend 引擎高效特性的基础上&#xff0c;引入了更清晰的扩展注册机制和增强的类型支持&#xff0c;使 C 语言编写的原生…

作者头像 李华
网站建设 2026/1/29 12:27:15

多传感器信息融合,卡尔曼滤波算法的轨迹跟踪与估计 AEKF——自适应扩展卡尔曼滤波算法

多传感器信息融合&#xff0c;卡尔曼滤波算法的轨迹跟踪与估计AEKF——自适应扩展卡尔曼滤波算法 AUKF——自适应无迹卡尔曼滤波算法 UKF——无迹卡尔曼滤波算法 三种不同的算法实现轨迹跟踪轨迹跟踪这活儿听起来高端&#xff0c;实际干起来全是坑。传感器数据像一群不听话的…

作者头像 李华
网站建设 2026/2/3 12:30:57

【NGS数据质控黄金法则】:10个R语言关键步骤确保分析可靠性

第一章&#xff1a;NGS数据质控的核心意义与R语言优势高通量测序&#xff08;NGS&#xff09;技术的迅猛发展为基因组学研究提供了前所未有的数据规模&#xff0c;但原始测序数据中常包含接头污染、低质量碱基和PCR重复等问题&#xff0c;直接影响后续分析的准确性。因此&#…

作者头像 李华
网站建设 2026/2/3 10:28:57

boost获取dll导出函数调用(C++源码)

1、概述 boost获取dll导出函数并调用,4个步骤。 1、包含头文件 2、加载dll 3、获取函数地址 4、调用函数 与windows 的GetProcessAdress方式相比,感觉boost更麻烦一点,于是用ai搜索了下区别,我觉得其中一个好处就是支持跨平台吧。 由于boost::dll::shared_library::get&…

作者头像 李华