JavaScript中'a'['toUpperCase']()的工作方式和原因是什么?

时间:2013-03-27 13:17:08

标签: javascript function

JavaScript让我感到惊讶,这是另一个例子。我刚刚遇到了一些我最初没有理解的代码。所以我调试了它并得出了这个发现:

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

现在,如果将toUpperCase()定义为字符串类型的成员,这一点必须明显,但最初对我没有意义。

反正

  • 这是否有效,因为toUpperCase是'a'的成员?或者幕后还有其他事情发生?
  • 我正在阅读的code具有以下功能:

    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
    

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

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

12 个答案:

答案 0 :(得分:293)

要打破它。

  • .toUpperCase()String.prototype
  • 的方法
  • 'a'是原始值,但会转换为对象表示
  • 我们有两种可能的符号来访问对象属性/方法,点和括号表示法

所以

'a'['toUpperCase'];

是来自toUpperCase的属性String.prototype上的括号表示法的访问权限。由于此属性引用方法,我们可以通过附加()

来调用它
'a'['toUpperCase']();

答案 1 :(得分:77)

foo.barfoo['bar']相同,因此您发布的代码与

相同
alert('a'.toUpperCase())

使用foo[bar]时(注意缺少引号),您不使用文字名bar,而是使用变量bar包含的任何值。因此,使用foo[]表示法而不是foo.可以使用动态属性名称。


我们来看看callMethod

首先,它返回一个以obj为参数的函数。执行该函数时,它将在该对象上调用method。因此,给定的方法只需要存在于obj本身或其原型链的某个地方。

如果toUpperCase该方法来自String.prototype.toUpperCase,那么对于存在的每个字符串都有一个单独的方法副本是相当愚蠢的。

答案 2 :(得分:25)

您可以使用.propertyName表示法或["propertyName"]表示法访问任何对象的成员。这是JavaScript语言的特性。要确保该成员在对象中,只需检查它是否已定义:

function callMethod(method) {
    return function (obj) {
        if (typeof(obj[method]) == 'function') //in that case, check if it is a function
           return obj[method](); //and then invoke it
    }
}

答案 3 :(得分:17)

基本上,javascript将所有内容视为Object,或者更确切地说,每个对象都可以视为字典/关联数组。并且函数/方法的定义方式与对象完全相同 - 作为此关联数组中的条目。

基本上,你引用/调用(注意' () ')' toUpperCase' ;财产,' a' object(在这种情况下是字符串类型)。

这里有一些顶尖的代码:

function myObject(){
    this.msg = "hey there! ;-)";
    this.woop = function(){
        alert(this.msg); //do whatever with member data
    }
}

var obj = new myObject();
alert( obj.msg );
alert( obj['msg'] );
obj['woop']();

答案 4 :(得分:10)

anyObject['anyPropertyName']没有问题字符时,

anyObject.anyPropertyNameanyPropertyName相同。

请参阅MDN上的Working with Objects

toUpperCase方法附加到String类型。当您在原始值上调用函数时,'a'会自动将其提升为对象,此处为String

  

在要在原始字符串或a上调用方法的上下文中   发生属性查找时,JavaScript会自动换行字符串   原语并调用方法或执行属性查找。

您可以通过记录String.prototype.toUpperCase来查看该功能。

答案 5 :(得分:9)

因此,在Javascript中,objectsobjects。那就是他们具有这种性质{}。可以使用以下任一项设置对象属性:a.greeting = 'hello';a['greeting'] = 'hello';。两种方式都有效。

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

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

但是,编写地图功能的更好方法是作为

var caps = ['a','b','c'].map( function(char) { return char.toUpperCase(); } )

谁需要callMethod功能?

答案 6 :(得分:6)

每个JavaScript对象都是一个哈希表,因此您可以通过指定密钥来访问其成员。例如,如果变量是一个字符串,那么它应该具有toUpperCase函数。所以,您可以通过

调用它
var str = "a"
str['toUpperCase'](). // you get the method by its name as a key and invoke it.

所以,通过内联str,你可以在

之下
"a"["toUpperCase"]()

答案 7 :(得分:6)

toUpperCase是一种标准的javascript方法:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase

它像'a'['toUpperCase']()一样工作的原因是toUpperCase函数是字符串对象'a'的属性。您可以使用object[property]object.property在对象上引用属性。语法'a''toUpperCase'表示您正在引用'a'字符串对象的'toUppercase'属性,然后调用它()。

答案 8 :(得分:4)

  

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

没有。有人可以传入一个

的对象
  1. 没有名为toUpperCase的媒体资源;或
  2. 有一个名为toUpperCase的属性,它不是一个函数
  3. 在第一种情况下,将抛出错误,因为访问不存在的属性会返回undefined,并且我们无法将undefined作为函数调用。

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

    请记住,JavaScript是一种非常松散的语言。很少或没有类型检查发生,除非并且直到它必须。您显示的代码在某些情况下有效,因为在这些情况下,传递的对象具有名为toUpperCase的属性,这是一个函数。

    obj参数不能保证具有正确类型的属性这一事实根本不会打扰JavaScript,可以这么说。它采用“观望”态度,并且在运行时发生实际问题之前不会抛出错误。

答案 9 :(得分:4)

几乎javascript中的所有内容都可以视为对象。在您的情况下,字母表本身充当字符串对象,toUpperCase可以作为其方法调用。方括号只是访问对象属性的替代方法,因为toUpperCase是一种方法,因此()形成['toUpperCase']旁边需要简单括号['toUpperCase']()

'a'['toUpperCase']()相当于'a'.toUpperCase()

'a'['toUpperCase']() // returns A
'a'.toUpperCase() // returns A

答案 10 :(得分:3)

这里需要注意的重要一点是,由于Javascript是一种dynamic语言,因此每个对象实际上只是一个美化的哈希图with a few exceptions)。并且可以通过两种方式访问​​Javascript对象中的所有内容 - 括号表示法和点符号。

我会快速回答你问题第一部分的两个符号,然后我会进入第二部分。

括号符号

此模式更类似于访问其他编程语言中的哈希映射和数组。您可以使用此语法访问任何组件(数据(包括其他对象)或功能)。

这正是您在示例中所做的。你有'a',这是一个字符串(和不是一个字符文字,就像用C ++这样的语言)。

使用括号表示法,可以访问其toUpperCase方法。但访问它仍然是不够的;只需在Javascript中键入alert,就不会调用该方法。这只是一个简单的陈述。为了调用该函数,您需要添加括号:alert()显示一个包含undefined的简单对话框,因为它没有接收任何参数。我们现在可以使用这些知识来破译您的代码,该代码变为:

alert('a'.toUpperCase());

哪个更具可读性。

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

alert(alert)

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

function alert() { [native code] } 

通话:

alert(alert())

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

Try out all the cases on jsFiddle!

点符号

这是更标准的方法,它允许使用点(.)运算符访问对象的成员。这是您的代码在点表示法中的样子:

alert('a'.toUpperCase())

更具可读性。那么我们何时应该使用点表示法,何时应该使用括号表示法?

比较

两种方法的主要区别在于语义。还有其他一些细节,但我会在一秒钟之内找到这些细节。最重要的是你真正想要做的事情 - 一个经验法则是你使用点符号来建立一个对象具有完善的字段和方法,以及括号 - 当您实际使用对象作为哈希映射时,表示法

为什么这个规则如此重要的一个很好的例子可以在你的例子中显示 - 因为代码在点符号更加明智的地方使用括号表示法,这使代码更难阅读。这是一件坏事,because code is read many more times than it is written

在某些情况下,即使使用点符号更明智,也必须使用括号表示法

  • 如果对象的成员的名称包含一个或多个空格或任何其他特殊字符,则不能使用点表示法:foo.some method()不起作用,但{ {1}}确实;

  • 如果您需要动态访问对象的成员,您还会使用括号表示法;

示例:

foo["some method"]()

最重要的是,在将对象用作哈希映射(for(var i = 0; i < 10; ++i) { foo["method" + i](); } )时使用括号语法,使用&#34;实际&#34;时使用点语法。字段和方法(foods["burger"].eat())。使用Javascript作为动态语言,&#34;实际&#34;之间的界限。对象的字段和方法以及&#34;其他&#34;存储在其中的数据会变得相当模糊。但只要你不以混乱的方式混合它们,你应该没事。


现在,问题的其余部分(最后!:P)。

  

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

你不能。试试吧。尝试在字符串上调用enemy.kill()。您将收到以下行中的错误:

derp
  

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

是的,在你的情况下,它必须是。否则你最终会得到我上面提到的错误。但是,您不必 Uncaught TypeError: Object a has no method 'derp' 函数中使用return obj[method]();。您可以添加自己的功能,然后由地图功能使用。这是一种硬编码方法,可将所有字母转换为大写字母:

callMethod()

您链接到的教程中的代码使用partial functions。它们本身就是一个棘手的概念。阅读有关该主题的更多信息应该有助于使事情比我做得更清楚。


注意:这是问题source here中代码使用的地图函数的代码。

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

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

答案 11 :(得分:2)

如果你问它是如何实际工作的,那就是我读它的方式。好的,这是一个简单的数学函数。要理解它,您需要查看ascii表。其中为每个字母分配一个数值。为了掩盖它,竞争只是使用逻辑陈述来掩盖,例如 If(ChcrValue&gt;&amp;&amp; charValue&lt; 106)//这是一组小写字母 然后charValue = charValue - 38; //下部集合和上部集合之间的距离

就这么简单,我实际上并没有费心去查找正确的值,但这基本上是将所有小写字母转换为大写字母。