javascript - 为什么 javascript 不首先检查对象的本地范围?

标签 javascript

为什么不能在内部范围访问外部范围?

我来自 C++ 世界,在这个世界中,任何对类方法内非限定变量的引用都试图首先在对象范围内解析,然后在外部范围内解析。无需使用“this”关键字即可发生这种情况。 例如:

#include <iostream>
using namespace std;

std::string name = "Global::name";

class MyClass {
    private:
        string name = "MyClass::name";
    public:
        void printName() {
            // No need to use 'this' keyword to refer to the variables in the
            // object's scope, unless there is an ambiguity to resolve
            cout << "Name from inside printName is: " << name << "\n";
        }
};

int main()
{
    MyClass obj;
    cout << "Name from inside main is: " << name << "\n";
    obj.printName();
    return 0;
}

打印

Name from inside main is: Global::name                                                                 
Name from inside printName is: MyClass::name

但是在javascript中,如下代码片段

function fn() {
    let name1 = "fnB";
    console.log("Inside fn() name is : ", name1);
}


var obj = {
    name1: "objA",
    objFn: function() {
        console.log("Inside objFn() name is : ", name1); // ERROR !!
        // console.log("Inside objFn() name is : ", this.name1); // OK !
    }
}

fn();
obj.objFn();

结果

Uncaught ReferenceError: name1 is not defined
    at Object.objFn (my.js:10)

javascript 不想在“obj”对象范围内引用“name1”变量而不需要“this”关键字来引用它的原因是什么?在此上下文中强制使用“this”关键字可以解决什么问题?

最佳答案

每种语言都是不同的,并且会做出不同的权衡。 C++ 和 JavaScript 在类/对象方法方面的明显区别:

  • 在 JavaScript 中,每个函数都是一个独立的对象。它不强烈属于任何东西。
    • 在C++中,类方法属于类。没有它就无法调用它们。
  • 在 JavaScript 中,每个函数都是一个闭包,即它可以访问定义在“更高”词法范围内的自由变量。
    • 在 C++ 中,方法不是闭包。

为什么这很重要?考虑以下示例:

var name = 42;

var obj = {
    name: "objA",
    objFn: function() {
        console.log("Inside objFn() name is : ", name);
    }
}

哪个name应该objFn按照您的预期访问?

就像现在一样,该函数将记录 42 ,因为这就是词法作用域 + 闭包的工作方式。为了访问对象的name属性(property)我必须写this.name .

现在假设情况正好相反,对象属性将在外部作用域之前被访问。然后为了显式访问外部作用域的变量,即 42 ,我们需要一些新的 API,例如getVariableFromScope('name') .这比总是需要 this 更糟糕原因很简单:这使得对代码进行推理变得更加困难。通过始终要求 this ,规则非常简单:

  • 想要访问对象的属性? this.<property>
  • 想要访问范围内的变量? <variable>

在您的情况下,它将是:

  • 想要访问范围内的变量? <variable> , 但前提是对象没有同名的属性,否则 getVariableFromScope('<variable>') .
  • 想要访问对象的属性? <property> , 但前提是没有同名的本地 变量,否则 this.<property> .

这里一个可能的权衡是一致性与便利性。

还请考虑以下示例:

var foo = 42;
function bar() {
  console.log(foo);
}

调用 bar()将记录 42 .现在假设我将函数传递给一些第三方代码 someOtherFunction(foo)这样做:

function someOtherFunction(func) {
  var obj = createObject();
  obj.func = func;
  obj.func();
}

你看到问题了吗?调用结果bar现在取决于是否obj有一个 name属性(property)与否。要解决此问题,someOtherFunction需要知道哪些自由变量 bar包含或 bar需要知道 someOtherFunction将它分配给某个对象并且必须考虑到这一点。无论哪种方式,代码都会紧密耦合。

做 C++ 或 Java 所做的基本上意味着引入 dynamic scope ,我认为很少有语言使用它是有原因的。

(有人可能会争辩说 this 也像动态作用域。好吧,this 是一个关键字。推理它比推理所有可能被覆盖的变量名的空间更容易。)


您所描述的行为在 JavaScript 中不可取的原因可能有更多。但同样,编程语言设计全都与权衡有关。

关于javascript - 为什么 javascript 不首先检查对象的本地范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54560442/

相关文章:

javascript - 使用 JS Fetch API 的 PHP POST

javascript - 从子窗口访问父窗口id

javascript - 将 jQuery 存储在一个变量中然后提醒它

javascript - react useEffect 和 mousedown 监听器

javascript - 带有多个参数和 xhr 的 Jquery $.when

javascript - 切换在多个类中单击的类 - DOM

javascript - 文本不在第二行拆分

javascript - 当高度是限制因素时保持 div 比率

javascript - 无法通过webapi在浏览器angularjs中显示文件

javascript - 单击单选按钮显示日历以及 jquery 中的一个输入框