JavaScript一直让我惊讶,这是另一个例子。我只是遇到了一些代码,一开始我不理解。所以我对它进行了调试,得到了这样的发现:

alert('a'['toUpperCase']());  //alerts 'A'

现在,如果toUpperCase()被定义为string类型的成员,这肯定是显而易见的,但最初对我来说没有意义。

不管怎么说,

does this work because toUpperCase is a member of 'a'? Or there is something else going on behind the scenes? the code I was reading has a function as follows: function callMethod(method) { return function (obj) { return obj[method](); //**how can I be sure method will always be a member of obj** } } var caps2 = map(['a', 'b', 'c'], callMethod('toUpperCase')); // ['A','B','C'] // ignoring details of map() function which essentially calls methods on every // element of the array and forms another array of result and returns it It is kinda generic function to call ANY methods on ANY object. But does that mean the specified method will already be an implicit member of the specified object?

我确信我对JavaScript函数的基本概念缺少一些认真的理解。请帮助我理解这一点。


当前回答

在Javascript中,对象就是对象。这就是它们的性质{}。对象属性可以使用以下任意一种来设置:a.greeting = 'hello';或者a['greeting'] = 'hello';。两种方法都有效。

检索的工作原理相同。a.greeting(不带引号)是'hello', a['greeting']是'hello'。例外:如果属性是一个数字,则只有括号方法有效。点方法没有。

a是一个带有toUpperCase属性的对象它实际上是一个函数。您可以检索该函数并随后以'a'.toUpperCase()或'a'['toUpperCase']()两种方式调用它。

但在我看来,更好的方法来写地图函数将是 Var caps = ['a','b','c']。map(函数(char){返回char. touppercase ();}) 那么谁需要callMethod函数呢?

其他回答

把它分解。

.toUpperCase()是String.prototype的一个方法 'a'是一个基本值,但会转换为它的Object表示形式 我们有两种可能的表示法来访问对象属性/方法,点表示法和括号表示法

So

'a'['toUpperCase'];

是String.prototype中通过括号符号对属性toUpperCase的访问。由于此属性引用了一个方法,因此可以通过attach()调用它。

'a'['toUpperCase']();

anyObject['anyPropertyName']与anyObject相同。当anyPropertyName没有问题字符时。

参见MDN中的“使用对象”。

toUpperCase方法附加到类型String上。当你在一个基本值上调用一个函数时,这里'a',它会自动提升为一个对象,这里是String:

在要对基本字符串或对象调用方法的上下文中 属性查找时,JavaScript会自动换行字符串 元素,并调用该方法或执行属性查找。

你可以通过记录String.prototype.toUpperCase来看到这个函数的存在。

这里需要注意的重要一点是,由于Javascript是一种动态语言,因此每个对象本质上都只是一个美化过的哈希映射(有少数例外)。Javascript对象中的所有内容都可以通过两种方式访问——括号表示法和点表示法。

我会快速地过一遍这两个符号来回答你问题的第一部分,然后我会讲第二部分。

括号

这种模式更类似于访问其他编程语言中的hashmap和数组。您可以使用此语法访问任何组件(数据(包括其他对象)或函数)。

这正是您在示例中所做的。你有一个'a',它是一个字符串(而不是字符字面量,就像在c++等语言中那样)。

使用括号符号,您可以访问它的toUpperCase方法。但仅仅获取信息还不够;例如,简单地在Javascript中输入alert,并不会调用该方法。这只是一个简单的陈述。为了调用函数,您需要添加圆括号:alert()显示了一个包含undefined的简单对话框,因为它没有接收到参数。我们现在可以利用这些知识来破译你的代码,它变成:

alert('a'.toUpperCase());

这样可读性更强。

实际上,更好地理解这一点的一个好方法是执行以下Javascript:

alert(alert)

它通过传递一个函数对象来调用alert,同样是alert,而不执行第二个alert。所显示的内容(至少在Chrome 26中)如下:

function alert() { [native code] } 

调用:

alert(alert())

显示包含undefined的两个连续消息框。这很容易解释:内部alert()首先被执行,显示为undefined(因为它没有任何参数)并且没有返回任何东西。外部警报接收内部警报的返回值-这是空的,并且在消息框中显示为undefined。

在jsFiddle上尝试所有的案例!

点符号

这是一种更标准的方法,允许使用点(.)操作符访问对象的成员。这是你的代码在点表示法下的样子:

alert('a'.toUpperCase())

可读性更强。什么时候用点符号,什么时候用括号符号?

比较

这两种方法的主要区别在于语义。还有一些其他细节,但我马上就会讲到。最重要的是您实际想要做什么——经验法则是,对于对象拥有的已建立的字段和方法使用点表示法,当您实际将对象用作哈希映射时使用括号表示法。

为什么这个规则如此重要的一个很好的例子可以在你的例子中显示出来——因为代码在点表示法更有意义的地方使用了括号表示法,这使得代码更难阅读。这是一件坏事,因为代码被读取的次数要比编写的次数多得多。

在某些情况下,你必须使用括号符号,即使使用点符号更明智:

如果对象成员的名称包含一个或多个空格或任何其他特殊字符,则不能使用点符号:foo。Some method()不起作用,但foo[" Some method"]()起作用; 如果你需要动态访问一个对象的成员,你也会使用括号符号;

例子:

for(var i = 0; i < 10; ++i) {
   foo["method" + i](); 
 }

底线是,当使用对象作为哈希映射(foods["burger"].eat())时,应该使用括号语法,当使用“实际”字段和方法时,应该使用点语法(enemy.kill())。由于Javascript是一种动态语言,对象的“实际”字段和方法与存储在其中的“其他”数据之间的界限可能会非常模糊。但只要你不把它们混在一起,就不会有问题。


现在,你的问题(终于!): P)。

我怎么能确定方法将永远是obj的成员

你不能。试一试。尝试在字符串上调用derp。你会得到一个如下的错误:

Uncaught TypeError: Object a has no method 'derp' 

在任意对象上调用任意方法是一种通用函数。但 这是否意味着指定的方法已经是隐式成员 指定对象的?

是的,在你的情况下,它必须是。否则就会出现我上面提到的错误。但是,你不必使用return obj[method]();在callMethod()函数中。您可以添加自己的功能,然后由映射函数使用。下面是一个硬编码的方法,将所有的字母转换为大写字母:

function makeCap()
{
    return function(obj) {
        return obj.toUpperCase();
    }
}

var caps2 = map(['a', 'b', 'c'], makeCap()); // ['A','B','C'] 
console.log(caps2)

您链接到的教程中的代码使用了部分函数。它们本身就是一个棘手的概念。多读一些这方面的书会让你更清楚一些。


注意:这是问题中代码使用的映射函数的代码,源代码在这里。

function map(arr, iterator) {
  var narr = [];
  for (var i = 0; i < arr.length; i++) narr.push(iterator(arr[i], i));
  return narr;
}

但这是否意味着指定的方法已经是指定对象的隐式成员?

不。有人可以传入一个对象

没有名为toUpperCase的属性;或 有一个名为toUpperCase的属性,不是一个函数

在第一种情况下,将抛出一个错误,因为访问不存在的属性将返回undefined,并且我们不能将undefined作为函数调用。

在第二种情况下,将抛出一个错误,因为我们不能将非函数作为函数调用。

请记住,JavaScript是一种非常松散类型的语言。除非必须进行类型检查,否则很少或根本不进行类型检查。您展示的代码在某些情况下是有效的,因为在这些情况下,传递的对象有一个名为toUpperCase的属性,这是一个函数。

可以这么说,obj参数不能保证具有正确类型的属性这一事实根本不会影响JavaScript。它采用“等待和观察”的态度,直到在运行时出现实际问题时才抛出错误。

在Javascript中,对象就是对象。这就是它们的性质{}。对象属性可以使用以下任意一种来设置:a.greeting = 'hello';或者a['greeting'] = 'hello';。两种方法都有效。

检索的工作原理相同。a.greeting(不带引号)是'hello', a['greeting']是'hello'。例外:如果属性是一个数字,则只有括号方法有效。点方法没有。

a是一个带有toUpperCase属性的对象它实际上是一个函数。您可以检索该函数并随后以'a'.toUpperCase()或'a'['toUpperCase']()两种方式调用它。

但在我看来,更好的方法来写地图函数将是 Var caps = ['a','b','c']。map(函数(char){返回char. touppercase ();}) 那么谁需要callMethod函数呢?