3 回答
![?](http://img1.sycdn.imooc.com/545861f00001be3402200220-100-100.jpg)
TA贡献1817条经验 获得超14个赞
好吧,它相当于'aaa'.toUpperCase.apply('abc')
,如果有帮助的话。
在 JavaScript 中,对象实际上只是关联数组。当数组键字符串(在本例中)具有标识符的形式时,点符号foo.bar
只是一种方便的简写方式 - 所有字母加上一些下划线,以及数字,只要它不以一个开头。foo['bar']
bar
因此,当您在对象上调用方法时,您实际上只是在查找存储在数组槽中的值,该值的键是方法名称。对于方法,该值是一个函数或“闭包”,然后您可以使用()
语法调用它。
但是对于方法名称,对象本身的槽通常实际上是空的!这会导致 Javascript 在所有相同类型的对象共享的原型对象上查找它;这就是 JavaScript 基于原型的继承的工作方式。在您的情况下,字符串'aaa'
实际上并没有在 key 下存储任何内容toUpperCase
,因此 JS 查看 String 原型以找到它。这样所有的字符串都有一组通用的方法,你可以调用它们——而不必在程序中的每个字符串中存储这些方法的副本。
就其本身而言,'aaa'.toUpperCase
只是另一个惰性值。它恰好代表一个函数(或闭包),但在你做一些事情让它运行之前,它并不比数字或字符串更活跃。您可以将它传递给其他方法调用,将其存储在其他变量或属性中,对它进行任何您想做的事情。
一旦你调用它,它就会得到一个this
调用者——方法调用内部的值——这取决于调用与属性查找相关的位置。通常,您只需在从对象中检索它的同一表达式中立即调用方法,在这种情况下,调用者就是同一个对象。这种行为在工作中更像是 JavaScript 语法魔法;foo.bar()
是一种有效的快捷方式foo.bar.apply(foo)
,使您不必重复对象表达式foo
。
如果您复制该方法并在没有显式对象引用的情况下调用它,它将this
从调用上下文继承 的值。并且可能会抱怨引用的对象不是预期的类型。
但是方法本身也是对象,它们有自己的方法,您可以对它们进行调用,包括一个apply
可以让您使用传入对象作为调用者调用方法的方法。这就是您的代码所做的 - 通过查找方法,'aaa'
然后实际调用它'abc'
。
![?](http://img1.sycdn.imooc.com/545850a00001fdd002200220-100-100.jpg)
TA贡献1780条经验 获得超4个赞
首先,它实际上相当于''.toUpperCase.apply('abc')
. 左边字符串的内容toUpperCase
没有区别。这是什么意思?toUpperCase
是 JavaScript 中每个字符串都可用的函数。并且apply
是 JavaScript 中每个函数都可用的函数。它可用于更改this
函数内部的值。
所以,如果你这样拆分你的代码,你就会明白发生了什么:
const upperCase = ''.toUpperCase; upperCase.apply('abc'); // ABC
碰巧 String#toUpperCase 使用this
内部的值转换为大写。
![?](http://img1.sycdn.imooc.com/545850ee0001798a02200220-100-100.jpg)
TA贡献1839条经验 获得超15个赞
从文档:
所有 String 实例都继承自 String.prototype。对 String 原型对象的更改会传播到所有 String 实例。
所以所有的字符串都继承了一系列的方法和属性,并且因为你可以使用dot或 square来访问属性notation。
因此这段代码:
'aaa'['toUpperCase'].apply('abc'); // ABC
相当于:
'aaa'.toUpperCase.apply('abc'); // ABC
也相当于:
String.prototype['toUpperCase'].call('Hello')
// or
String.prototype.toUpperCase.call('Hello')
apply并且也是call继承自Function.prototype并允许在Javascript中执行函数的函数。
添加回答
举报