来自C,每个函数都需要一个用于调用该特定函数的名称。但是在下面的JavaScript代码中。根本没有名字。那么function(func) { func(); }
如何调用something.push(function()
?
更不用说something.push(function()
甚至没有参数,从C角度来看,这是错误的
var something = [],
object = {
a: true,
b: true,
c: true
}
for (let key in object){
something.push(function() {
console.log(key);
});
}
something.forEach(function(func) { func(); }):
答案 0 :(得分:2)
来自C,每个函数都需要一个用于调用该特定函数的名称。但在下面的JavaScript代码中,根本没有名称。
在JavaScript中,情况并非如此 - 函数确实可以是匿名(无名)函数。有时你会听到它们被称为“lambdas”或冗余称为“lambda函数”。
但更重要的是,JavaScript中的函数是第一类数据成员,这意味着:
可以分配给变量
let y = x => x + 5
y(3)
// 8
他们可以作为参数传递给其他函数
let xs = [1,2,3]
let y = x => 2 * x
xs.map(y)
// [2,4,6]
他们可以从函数
返回let add = x => {
return y => x + y
}
let f = add(1)
f(2)
// 3
它们可以包含在数据结构中
let pikachu = {
number: 25,
shock: enemy => enemy.damage(30),
growl: enemy => enemy.sadden(40)
}
pikachu.growl(meowth)
// "It's very effective!"
那么这里拿走了什么?好吧,在JavaScript中,您需要将函数视为与任何其他值(例如)1
,"foo"
或[{user: 'bob'}, {user: 'alice'}]
没有区别 - 从概念上讲,它们只是数据而且他们都是一流的
如何理解您的代码
这是我亲切重新格式化的代码。既然你最初询问了ES6,我将用ES6替换你的lambdas arrow functions
let something = []
let object = { a: true, b: true, c: true }
for (let key in object) {
something.push(() => console.log(key))
}
something.forEach(func => func())
// a
// b
// c
使用高级描述符,此代码的性质是
object
的每个密钥,将某些值添加到something
something
的每个值进行迭代,使用该值执行某些操作在你的情况下,某个值是一个函数,但我想告诉你如果我们使用另一种值,你的代码会是什么样的
let something = []
let object = { a: true, b: true, c: true }
for (let key in object) {
// this time push a string, instead of an anonymous function
something.push("the key is: " + key)
}
something.forEach(str => console.log(str))
// the key is: a
// the key is: b
// the key is: c
现在我们可以看到当使用不同的值类型(String)时代码如何工作。除了使用字符串之外,我们唯一做的另一件事就是改变
// from
func => func()
// to
str => console.log(str)
这里的推理是
,something
是一个函数数组,因此对于每个函数func
,我们调用func()
< / p>
在修改过的代码中,something
是一个字符串数组,因此对于每个字符串str
,我们称之为console.log(str)
< / p>
解剖Array.prototype.forEach
要理解的最后一点是超级电源forEach
功能。请记住第一类功能中的点号 2 :第一类数据成员可以作为参数传递给其他函数。
forEach
期望它的论证是一个函数。所以forEach
是一个接受另一个函数的函数。这种功能称为higher-order function。
不要让这些花哨的名字分散你的注意力。制作像forEach
这样的高阶函数实际上非常简单。永远只记得功能与任何其他值一样 - 下面,我们将编写我们自己的forEach
版本,以便您可以看到它是如何工作的
let something = []
let object = { a: true, b: true, c: true }
// forEach accepts an array and some function, f
let forEach = (arr, f) => {
// iterate thru each value of arr
for (let value of arr) {
// call f on each value
f(value)
}
}
for (let key in object) {
something.push("the key is: " + key)
}
forEach(something, str => console.log(str))
// the key is: a
// the key is: b
// the key is: c
现在我们看到字符串数组使用我们自己的forEach
函数。让我们确保它也适用于原始的lambda数组。
let something = []
let object = { a: true, b: true, c: true }
let forEach = (arr, f) => {
for (let value of arr) {
f(value)
}
}
for (let key in object) {
something.push(() => console.log(key))
}
forEach(something, func => { func() })
// a
// b
// c
<强>说明强>
就是这样!函数不是JavaScript中的特殊雪花。它们就像所有的基准一样。
从C角度来看,以这种方式思考功能可能需要一段时间。但实际上,当你走进任何新编程语言的家时,你应该把你理解的所有语言都放在门口。每种语言都有自己的表达方式,产生一系列独特的优点和缺点。通过将某种语言A的“力量”引入另一种语言B,你可能会将B的自身优势之一替换为其中一个弱点。
JavaScript是一种多范式语言,使其非常适合命令式,面向对象和函数式编程风格。由于它具有万能的性质,它可能不是最好的 oop或fp语言,但它仍然相当令人印象深刻,它可以通过各种方式表达问题的特定解决方案
答案 1 :(得分:0)
JavaScript是比C更抽象的语言。在JavaScript解释器内部保存每个变量的类型和指针。声明一个函数时,它会在内部保存在内存中,并且该函数的指针将传递给您传递给它的任何内容(此处为something.forEach
)。
但是,这不是C中的指针,您无法访问其值(函数地址),也无法更改它。在JavaScript中,这些伪指针被称为&#34;引用&#34;。简单地说,当你尝试调用某些东西时,解释器引擎会检查它的类型。如果它的类型类型是一个函数,线程将做一些准备,然后执行跳转到函数指针所指向的内存位置。
答案 2 :(得分:0)
something
数组存储对函数的引用,但不调用它们。在forEach
循环中,正在调用数组中的每个函数。
公平地说,命名令人困惑。你可以这么容易地写:
something.forEach(function(storedFunction) { storedFunction(); }):
因为它是一个临时变量
答案 3 :(得分:0)
所以,这里发生了什么,我们在每次迭代时都pushing function
到something
。假设在这种情况下something
是一个数组。
然后,我们调用集合的foreach()函数。此函数中的第一个参数始终是我们迭代的当前项。在这种情况下,我们将迭代遍历在循环中构建的函数列表。由于这些是函数,我们可以调用它们,这是每个函数发生的事情。
以下是一个帮助说明的例子:
// declare some functions
function a(){console.log('hi');}
function b(){console.log('there');}
function c(){console.log('friend');}
const ar = [];
// push the functions to the array
ar.push(a);
ar.push(b);
ar.push(c);
ar.push(a);
ar.forEach(function(func) {func();});
// console output:
// hi
// there
// friend
// hi
编辑:我强烈建议您阅读Mozilla's documentation of the function type。如果你去那里并彻底阅读它,我想你会对这个概念有一个非常扎实的把握。
答案 4 :(得分:0)
在JavaScript中,函数被视为对象。在C中你必须意识到并非每个对象(值)都需要有一个名称,或者不需要存储在一个变量中。就像你可以拥有sum (4, 5);
一样。 4和5是未存储在变量中的值。
要回答关于如果没有名称将如何调用它们的问题,该函数将作为参数传递给push函数。那里的形式参数必须有一些名称。所以它可以被这个名字调用。在这种情况下,push不会调用它,但会将其存储在稍后要调用的数组中。它可以通过索引到数组来调用。
答案 5 :(得分:0)
您看到的是使用匿名函数和闭包。简而言之,它非常简洁。
在那里我描述了每个块的代码块:
我们创建一个数组(如C中所示):
var something = [],
我们创建一个对象(key = value的集合)
object = {
a: true,
b: true,
c: true
}
我们遍历对象的元素 对象
for (let key in object) {
该节目已开启:
something.push(function() {
每个对象都有一个push函数,允许在其中动态放置元素。 你在这里看到的是匿名函数被用作参数;这意味着对于此推送功能的每次执行,执行以下操作:
console.log(key);
将被放入某些数组;
之后,唯一做的是使用 func()的callback
:
something.forEach(function(func) { func(); }):
这意味着某些的 forEach 元素,您将其视为函数,从而导致调用 push存储的先前函数()