为什么不能在内部范围访问外部范围?
我来自 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/