JS中有参数的函数是否需要加参数

Is it necessary to add a argument to a function with parameters in JS

来自Java并正在尝试学习Java脚本,以下代码有效:

const myCustomDiv = document.createElement('div');

function respondToTheClick(evt) {
    evt.target.textContent = 'This paragraph has been clicked!'; 
}

for (let i = 0; i < 100; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    myCustomDiv.appendChild(newElement); 
}

document.body.appendChild(myCustomDiv);

myCustomDiv.addEventListener('click', respondToTheClick);

而下面的不是并且报错

const myCustomDiv = document.createElement('div');

function respondToTheClick(evt) {
    evt.target.textContent = 'This paragraph has been clicked!';
}

for (let i = 0; i < 100; i++) {
    const newElement = document.createElement('p');
    newElement.textContent = 'This is paragraph number ' + i;

    myCustomDiv.appendChild(newElement);
}

document.body.appendChild(myCustomDiv);

myCustomDiv.addEventListener('click', respondToTheClick(event) );  //<--added event argument

产生的错误是:

Argument type void is not assignable to parameter type (this:HTMLDivElement, ev: HTMLElementEventMap[string]) => any

使用 Java,如果方法需要参数 - 必须提供。 JS 不是这种情况吗——如果是这样,它是如何工作的?或者这只是 eventListeners 的情况?

在JavaScript中,函数是first-class对象。您可以对函数执行任何您可以对对象执行的操作。这包括将其作为函数的参数传递。

addEventListener("click", respondToTheClick)

… 传递 respondToTheClick 作为 addEventListener 的第二个参数。

addEventListener('click', respondToTheClick(event) );

相当于:

let return_value = respondToTheClick(event);
addEventListener('click', return_value);

addEventListener的第二个参数需要是一个函数。 respondToTheClick(event) 的 return 值不是函数。这就是您收到错误的原因。

当浏览器内置的某些其他代码在 addEventListener 函数内部调用您作为参数传递给它的函数时, 代码将通过它是一个事件对象作为参数。

function handleEvent(e) {
    console.log(e);
}

function addEventDemo(event_type, event_handler) {
    event_handler("E is " + event_type);
}

addEventDemo("click", handleEvent);


也就是说,JS 不要求您将参数传递给函数,即使它被设置为将参数分配给变量。任何您未定义的都将获得值 undefined.

function foo(a, b, c, d) {
    console.log({ a, b, c, d });
}

foo(1, 2);

虽然 JS 不需要它,但函数可以强制执行。

function foo(a, b, c, d) {
    if (typeof a !== "number") throw "a is not a number";
    if (typeof b !== "number") throw "b is not a number";
    if (typeof c !== "number") throw "c is not a number";
    if (typeof d !== "number") throw "d is not a number";
    console.log({ a, b, c, d });
}

foo(1, 2);

第一个示例是将函数 respondToTheClick 的引用传递给 addEventListener。该函数不会立即执行,而是注册(使用 addEventListener)以在事件发生时由浏览器执行。这在 java 脚本中称为 callback function

在第二个示例中,您将调用该函数,然后将该调用的 return 值作为参数传递给 addEventListener。例如,foo(sum(1, 2))3 传递给 foo,而不是函数 sum 本身。

在java脚本中,函数是对象,您可以像使用常规对象一样使用它们。它们也是可调用的(可以被调用)。在 javascript 中,与在 java 中一样,您可以将对象分配给不同的变量,这不会创建对象的新副本,而是会创建指向同一对象的不同变量.由于函数是 javascript 中的对象,因此以下内容有效并按预期工作:

function sayHi() {
  console.log("Hi");
}

// 'func' and 'sayHi' will point to the same object, the object being
// a function that prints "Hi" to the console. 
var func = sayHi;  


// although there was never a function defined called 'func', this
// will still work because of the above assignment
func();

现在,这正是问题中第一个示例中发生的情况,但不是将函数 respondToTheClick 分配给变量,而是将其作为参数传递给 addEventListener。从 addEventListener 调用参数类似于从上面的示例调用变量 func ;它将执行该功能。这就是回调在 javascript.

中的用途

在 java 中最接近回调的是 Method 反射的使用,如下所示:

public class SomeClass {
    public void sayHi(String name) {
        System.out.println("Hi " + name);
    }
}

/////////////////////////////////////////////////////////////////////////////

public class Example {
    public static void main(String[] args) {
        // get a reference to a method called 'sayHi' on the class 'SomeClass' that
        // has only one parameter of type String, we have to specify the type of
        // parameters because of method overloading (different methods can have the
        // same name in java and we distinguish between them using their parameters).
        // In javascript this can be done by a simple assignment, but again, that's javascript.
        Method theSayHiMethod = SomeClass.class.getMethod("sayHi", String.class);

        SomeClass inst = new SomeClass();

        // now we can pass the reference to 'sayHi' (or more accurately, its reflection)
        // without invoking it. Notice how 'addEventListener("click", respondToTheClick)'
        // is the same as:
        callAMethodOnObject(inst, theSayHiMethod);
    }

    public static void callAMethodOnObject(Object object, Method method) {
        // 'sayHi', 'theSayHiMethod' and 'method' are the exact same method, the latter
        // two are reflections. Invoking the reflections will execute the function
        // they reflect as if it was called directly. Since everything in java is
        // an instance of some class (there are no standalone functions), we have to
        // specify the context for the method, in this example it is 'object' which is
        // the an instance of 'SomeClass' where 'sayHi' is defined
        method.invoke(object, "World!");
    }
}

这在 java 中几乎从未使用过,因为如果您想要一个在某些事情发生时调用的方法(例如事件),您通常会传递包含该方法的整个对象它将通过直接在传递的对象上调用它来调用,如下所示:

class MyClickHandler implements ClickHandler {
    public void onClick(Event event) {
        // ...
    }
}

// then pass it to another method like so:

ClickHandler handler = new MyClickHandler();
someObject.setClickListener(handler);

// when a click happens, the method 'onClick' of 'handler' will be called. Javascript
// has the ability to pass the function directly without the need to wrap it in an
// object first.