dax*_*xim 2 javascript ruby python dynamic-languages sigils
动态语言允许从值仅在运行时获知的变量调度和调用值.Perl中的对比示例:
班级名称
不变
Foo::Bar->some_method
Foo::Bar::->some_method
'Foo::Bar'->some_method
Run Code Online (Sandbox Code Playgroud)这些都是相同的,除了第一个是边缘情况.如果在具有该名称的范围中定义了子例程,则调度发生在其返回值上,这导致难以理解的错误.引用的版本总是安全的.
动态
my $class_name = 'Foo::Bar';
$class_name->some_method
Run Code Online (Sandbox Code Playgroud)方法名称
不变
Some::Class->foo_bar
Run Code Online (Sandbox Code Playgroud)动态
my $method_name = 'foo_bar';
Some::Class->$method_name
Run Code Online (Sandbox Code Playgroud)功能名称
不变
foo_bar;
(\&foo_bar)->()
Run Code Online (Sandbox Code Playgroud)动态
my $function_name = 'foo_bar';
(\&$function_name)->()
Run Code Online (Sandbox Code Playgroud)我想知道,变量名称没有符号(通常或根本没有)的语言如何处理这些问题,特别是他们的语言设计者如何消除以下歧义?
FooBar.some_method,其中类FooBar可能是名称文字,或者是值为类名称的变量SomeClass.foo_barwhere方法foo_bar可能是name literal或其值是方法名称的变量foo_bar函数可能是名称文字或值为函数的变量我主要对这个问题标签中提到的三种语言感兴趣,但是如果你知道一种不同的动态语言,你也可以回答.
在python和js中(我的ruby有点生疏),在名称上下文中不可能使用字符串.如果您尝试这样做,那将被解释为对字符串本身的操作:
class_name = 'Foo'
object = class_name()
> TypeError: 'str' object is not callable
Run Code Online (Sandbox Code Playgroud)
首先应通过查找上下文/范围字典来解析字符串:
class Foo:
....
object = globals()['Foo']()
Run Code Online (Sandbox Code Playgroud)
要么
function Foo() ....
object = new window['Foo'];
Run Code Online (Sandbox Code Playgroud)
Python提供全局和本地dicts,js只提供全局dicts,因此除了无处不在的"eval"之外,从名称中获取本地值是没有办法的.
这同样适用于方法:使用getattr(python)或间接引用运算符[...](js)查找方法:
method_name = 'foo'
method = getattr(some_object, method_name)
method()
Run Code Online (Sandbox Code Playgroud)
Javascript代码稍微复杂一些,因为与python不同,返回的方法指针是未绑定的:
method_name = 'foo'
method = some_object[method_name].bind(some_object)
method()
Run Code Online (Sandbox Code Playgroud)
没有bind你将无法this在方法中得到正确的:
var obj = {
xyz: 42,
method: function() {
document.write(this.xyz)
}
}
var method_name = 'method';
var unbound_method = obj[method_name];
unbound_method() // prints undefined
var bound_method = obj[method_name].bind(obj);
bound_method() // prints 42Run Code Online (Sandbox Code Playgroud)
更正式地说,python/js中的点运算符.(相当于php ::和->)需要右侧的标识符,并允许左侧的任意表达式.由于一切都是对象,如果左侧表达式返回一个字符串,则该点应用于该字符串,而不是该字符串恰好等于的变量.
(作为旁注,在点的右侧允许表达式在技术上是可行的,因此foo.('bar' + 'baz')可以解决foo.barbaz.我不知道支持这种语法的语言,但它看起来像是一个很好的替代getattr方法和类似的方法).
类似地,调用运算符()允许左侧的复杂表达式,此外该表达式必须解析为"可调用"对象.因此,"someString"()没有意义,因为字符串通常不可调用(除非你以某种方式破解它们以便它们).
也就是说,如果您有一个包含变量名称的字符串,则必须在使用前明确解析它.在幕后为你做的那种语言没有神奇之处.