Home >Web Front-end >JS Tutorial >JavaScript Functions That Define and Rewrite Themselves
Dynamic features of JavaScript functions: self-definition and rewriting
Key points:
The dynamic nature of JavaScript means that functions can not only call themselves, but also define themselves, or even rewrite themselves. This is achieved by assigning anonymous functions to variables with the same name as the function.
Consider the following function:
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } }</code>
This function first outputs a message to the console and then rewrites itself to output a different message to the console. When the function is called once, it is defined like this:
<code class="language-javascript">function party() { console.log('Been there, got the T-Shirt'); }</code>
After the first call, each time the function is called, the message "Been there, got the T-Shirt" will be output:
<code class="language-javascript">party(); party(); party();</code>
If the function is also assigned to another variable, this variable will retain the original function definition and will not be rewritten. This is because the original function is assigned to a variable, and then inside the function, a variable with the same name as the function is assigned to another function. If we create a variable named before the first call and redefine and assign it to the beachParty
function, we can see this example: party()
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } } const beachParty = party; // 注意,party 函数尚未被调用 beachParty(); // party() 函数现在已被重定义,即使它没有被显式调用 party(); beachParty(); // 但此函数尚未被重定义 beachParty(); // 无论调用多少次,它都将保持不变</code>Properties are missing
property and see that it no longer exists after the function is called and redefined: music
<code class="language-javascript">function party() { console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } } party.music = 'Classical Jazz'; // 设置函数的属性 party(); party.music; // 函数现在已被重定义,因此属性不存在</code>This is called the Lazy Definition Pattern and is usually used when some initialization code is required on the first call. This means that initialization can be done on the first call, and then the function can be redefined as the function you want to use with each subsequent call.
This technique can be used with feature detection we discussed in the previous chapter to create functions that rewrite themselves, called init-time branching. This enables the function to work more efficiently in the browser and avoids checking for features every time it is called.
Let's take our fictional unicorn object, which is not fully supported in all browsers. In the previous chapter, we looked at how to use feature detection to check if this feature is supported. Now we can go a step further: we can define functions based on whether certain methods are supported. This means we only need to check the support when the function is called the first time:
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } }</code>
After checking whether the window.unicorn
object exists (by checking whether it is a true value), we override the ride()
function based on the result. At the end of the function, we call it again so that the rewritten function is now called and the relevant value is returned. It should be noted that the function is called twice the first time, although it becomes more efficient with each subsequent call. Let's see how it works:
<code class="language-javascript">function party() { console.log('Been there, got the T-Shirt'); }</code>
Once the function is called, it will be rewritten according to the browser's functions. We can check this by checking the function without calling it:
This can be a useful pattern for initializing functions when they are called the first time and optimizing them for the browser being used.
Recursive function refers to a function that calls itself until a certain condition is met. It is a useful tool when it comes to iterative processes. A common example is a function that calculates a factorial number:
<code class="language-javascript">party(); party(); party();</code>
If 0 is provided as the argument (0 is factorially 1), this function will return 1, otherwise it will multiply the argument by the result of calling itself with one less parameter than it. The function will continue to call itself until the final parameter is 0 and returns 1. This will result in multiplication of 1, 2, 3 and all numbers up to the original parameter.
Another example from the field of mathematics is the Collatz conjecture. This is a simple question to state, but has not been resolved so far. It involves taking any positive integer and following the following rules:
For example, if we start with the number 18, we will get the following sequence:
18, 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1 , …
As you can see, the sequence ends up falling into a loop, looping through "4,2,1". The Collatz conjecture states that each positive integer creates a sequence that ends with that loop. This has been verified for all numbers up to 5 × 2⁶⁰, but there is no evidence that it will continue to hold on all integers above this. To test this conjecture, we can write a function that uses recursion to keep calling the function until it reaches the value 1 (because we want our function to avoid ending up falling into a recursive loop!):
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } }</code>
This function takes a number as an argument, and another argument named sequence
, with a default value of an array containing the first argument. The second parameter is only used when the function calls itself recursively.
function does is to test whether the value of n
is 1. If so, the function returns a message indicating how many steps it took. If it does not reach 1, it checks whether the value of n
is an even number (in this case it divides it by 2), or an odd number, in this case it multiplies by 3 and adds 1. The function then calls itself, providing a new n
value and a new sequence as parameters. A new sequence is constructed by placing the old sequence and the values of n
in a new array and applying the expand operator to the old sequence.
Let's see what happens with the number 18:
<code class="language-javascript">function party() { console.log('Been there, got the T-Shirt'); }</code>
As you can see, it takes 21 steps, but eventually it ends at 1.
Try using this function and see if you can find a value greater than 5 × 2⁶⁰ that doesn't end at 1 - if you do, you'll become famous!
In JavaScript, you can use the Function
constructor to create functions dynamically. This constructor takes two parameters: a string containing a comma-separated list of parameter names, and a string containing the body of the function. For example, you could create a function that adds two numbers, like this:
<code class="language-javascript">party(); party(); party();</code>
This method allows you to define functions dynamically, but it is not generally recommended because it is not as efficient and error-prone as normal declaration of functions.
In JavaScript, functions can be self-defined, which means they can modify their own code at runtime. This is possible because functions in JavaScript are first-class objects, which means they can be passed, returned from other functions, and even modified. Here is an example of a function rewriting itself:
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } } const beachParty = party; // 注意,party 函数尚未被调用 beachParty(); // party() 函数现在已被重定义,即使它没有被显式调用 party(); beachParty(); // 但此函数尚未被重定义 beachParty(); // 无论调用多少次,它都将保持不变</code>
The first time foo()
is called, it rewrites itself. The next time foo()
is called, it will execute the new code.
In JavaScript, you can override the function by simply assigning a new function to the same variable. Here is an example:
<code class="language-javascript">function party() { console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } } party.music = 'Classical Jazz'; // 设置函数的属性 party(); party.music; // 函数现在已被重定义,因此属性不存在</code>
When you call foo()
, it executes the new function, not the original function. This is because the variable foo
now points to the new function.
Dynamic definition JavaScript functions can provide flexibility because you can dynamically create and modify functions according to your program's needs. However, it also has some disadvantages. It is not as efficient as declaring functions normally, because the JavaScript engine cannot optimize functions in advance. It is also more error-prone, because no errors in the function body string are caught before the function is executed.
Yes, you can use arrow functions to define and override JavaScript functions. Arrow functions provide a cleaner syntax and have some differences in handling this and other special keywords. Here is an example of defining and rewriting arrow functions:
<code class="language-javascript">function party(){ console.log('Wow this is amazing!'); party = function(){ console.log('Been there, got the T-Shirt'); } }</code>
When you call foo()
, it executes the new function, not the original function.
The above is the detailed content of JavaScript Functions That Define and Rewrite Themselves. For more information, please follow other related articles on the PHP Chinese website!