What's worse is that ECMAScript of IE implements JScript to seriously confuse the name function expression.
What's worse is that the implementation of JScript by ECMAScript of IE seriously obfuscated the name function expression, and many people have come out against the name function expression, and even the latest version (5.8 used in IE8) still has the following problems.
Next, let's take a look at the mistakes that IE has made in implementation. As the saying goes, we know that we know what we are and what we can do. Let's take a look at the following examples:
Example 1: The identifier of the function expression is leaked to the external scope.
var f = function g(){};typeof g; // "function"
As we have mentioned above, the identifier of the name function expression is invalid in the external scope, but JScript obviously violates this specification. In the above example, the identifier g is parsed as a function object, this is messy, and many bugs that are hard to find are caused by this reason.
Note: IE9 seems to have fixed this problem
Example 2: Use a naming function expression as both a function declaration and a function expression
typeof g; // "function"var f = function g(){};
In the feature environment, the function declaration takes precedence over the parsing of any expression. The preceding example shows that JScript uses the named function expression as the function declaration, because it resolves g before actual declaration.
This example introduces the next example.
Example 3: The name function expression creates two completely different function objects!
var f = function g(){}; f === g; // false f.expando = 'foo'; g.expando; // undefined
Here, we will think the problem is serious, because it is too evil to modify any object and the other one has no changes. In this example, we can find that two different objects are created, that is, if you want to modify the attributes of f to save a certain information, then, if you reference the g attribute of the same object to use the attribute of the same name, the problem is big, because it is impossible.
Let's take a look at a slightly complex example:
Example 4: Only sequential parsing function declaration and ignore conditional statement Blocks
var f = function g() { return 1; }; if (false) { f = function g(){ return 2; }; } g(); // 2
This bug is much more difficult to find, but the cause of the bug is very simple. First, g is parsed as a function declaration. Since function declaration in JScript is not restricted by conditional code blocks, in this very bad if branch, g is treated as another function g () {return 2} is declared again. Then, all "regular" expressions are evaluated, and f is assigned a reference to another newly created object. Since the expression value will never enter the "this hateful if branch", f will continue to reference the first function g () {return 1 }. After the analysis, the problem is very clear: if you call g in f, it will call an unrelated g function object.
You may ask, what is the difference between different objects and arguments. callee? Let's take a look:
var f = function g(){ return [ arguments.callee == f, arguments.callee == g ]; }; f(); // [true, false] g(); // [false, true]
As you can see, the reference of arguments. callee is always called function. In fact, this is also a good thing and will be explained later.
Another interesting example is to use a namefunction expression in a value assignment statement that does not contain a declaration:
(function(){ f = function f(){}; })();
According to code analysis, we originally wanted to create a global attribute f (Be sure not to confuse it with a normal anonymous function, which uses a name-based life ), JScript makes a mess here. First, it resolves the expression as a function declaration, So f on the left is declared as a local variable (just like the Declaration in a general anonymous function ), then, when the function is executed, f is already defined, and function f () {} on the right is directly assigned to the local variable f, therefore, f is not a global attribute at all.
After learning about the abnormal nature of JScript, we need to prevent these problems in time. First, prevent identifier leakage with external scopes. Second, we should never reference the identifier used as the function name; do you still remember the annoying identifier g in the previous example? -- If g does not exist, we can avoid unnecessary troubles. Therefore, the key is to always reference a function through f or arguments. callee. If you use a name function expression, you should only use that name during debugging. Finally, remember to clean up the functions that are incorrectly created during the namefunction expression declaration.
Additional reading
The topic list of this article is as follows:
- How should we understand the working principle of the JavaScript engine?
- JavaScript exploration: the importance of writing maintainable code
- JavaScript exploration: exercise caution when using global variables
- JavaScript exploration: var pre-parsing and side effects
- JavaScript exploration: for Loop (for Loops)
- JavaScript exploration: for-in loop (for-in Loops)
- Exploring JavaScript: Prototypes is too powerful
- JavaScript: eval () is the devil"
- JavaScript exploration: Using parseInt () for Numerical Conversion
- Exploring JavaScript: Basic coding specifications
- JavaScript exploration: function declaration and function expression
- JavaScript exploration: Name function expressions
- JavaScript: function name in the debugger
- JavaScript: JScript Bug
- JavaScript exploration: Memory Management of JScript
- Exploring JavaScript: SpiderMonkey's quirks
- JavaScript exploration: an alternative solution to naming function expressions
- JavaScript exploration: Object
- JavaScript exploration: Prototype chain
- JavaScript exploration: Constructor
- JavaScript probing: executable context Stack
- Execution context 1: Variable object and activity object
- Execution context 2: Scope chain Scope Chains
- Execution context 3: Closure Closures
- Execution context 4: This pointer
- Exploring JavaScript: Powerful prototype and prototype chain
- JavaScript Functions 1: function declaration
- JavaScript function 2: function expressions
- JavaScript function 3: function expressions in a group
- JavaScript function 4: function Constructor
- JavaScript variable object 1: VO Declaration
- JavaScript variable object 2: VO in different execution contexts
- JavaScript variable object 3: two stages of execution Context
- JavaScript variable object IV: Variables
- Property of the JavaScript variable object __parent _
- JavaScript scope chain 1: Scope chain Definition
- JavaScript scope chain 2: function Lifecycle
- JavaScript scope chain 3: Scope chain features
- JavaScript closure 1: Introduction to closures
- JavaScript closure 2: Implementation of closure
- JavaScript closure 3: Closure usage
This article is available at http://www.nowamagic.net/librarys/veda/detail/1636.