Home  >  Article  >  Web Front-end  >  Detailed explanation of delete usage in javascript_javascript skills

Detailed explanation of delete usage in javascript_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:37:341324browse

In this article, the author starts from the error about delete in the book "JavaScript Object-Oriented Programming Guide" and details the implementation, limitations and problems of delete operation in different browsers and plug-ins (here refers to firebug) performance.

The main parts are translated below.

...claims in the book

“A function is just like an ordinary variable - it can be copied to different variables or even deleted”

And attached the following code snippet as an explanation:

Copy the code The code is as follows:

>>> var sum = function(a, b) {return a b;};
>>> var add = sum;
>>> delete sum;
true
>>> typeof sum;
"undefined"

Can you spot the problem in the clip? The problem is - deleting the sum variable should not succeed; the delete declaration should not return true and typeof sum should not return undefined. Because variables cannot be deleted in JavaScript, at least not in this way.

So what’s going on in this example? Is it a typo or a joke? Probably not. This snippet is an actual output from the firebug console that Stoyan (the author of the book mentioned above) supposedly used for a quick test. This seems to indicate that firebug has some different deletion rules. It was firebug that misled Stoyan! So what's going on here?

To answer this question, we need to understand how the delete operator works in Javascript: what can be deleted, what cannot be deleted and why. Below I try to explain the details of this. We'll look at Firebug's "weird" behavior and realize that it's actually not "weird" at all; we'll get into the details behind the scenes when we declare variables, functions, assign properties, and delete them; We'll look at browser implementations and some famous bugs; we'll also discuss strict mode in ECMAScript version 5 and how it changes the behavior of the delete operator.

I use Javascript and ECMPScript interchangeably below to generally refer to ECMAScript (except when explicitly referring to Mozilla's JavaScript™ implementation).

As expected, there are currently very few explanations of delete on the Internet (Author's note: This article was written in January 2010). The MDC (MDN]) resource is probably the most detailed out there, but unfortunately it leaves out some interesting details, including the strange behavior of the firebug mentioned above. MSDN documentation is almost useless.

1. Theory | Theory
So, why can we delete the attributes of an object:

Copy Code The code is as follows:

var x = { a: 1 };
delete x.a; // true
x.a; // undefined


But you cannot delete a variable:
Copy code The code is as follows:

var x = 1;
delete x; // false;
x; // 1

You cannot delete a function either:
Copy code The code is as follows:

function x() {};
delete x; // false;
typeof x; // "function"

Note: delete only returns false if a property cannot be deleted.

In order to understand this, we need to first grasp some concepts: variable instantiation and property attributes (Translator’s note: For the difference between property and attributes, see the reference article, according to The content involved below is intended to be translated into internal properties) - these are rarely mentioned in JavaScript books. In the following paragraphs I will try to briefly review these, it is not difficult to understand them. If you are not interested in the reasons behind their performance, you can skip this chapter.

1.1 Type of code | Type of code

There are three types of executable code in ECMAScript:

1.Global code Global code
2. Function code Function code
3.Eval code

The categories pretty much mean what they are named, but a quick recap:

1. When a source file is regarded as a program, it is executed within the global scope (scope), and this is considered a piece of global code Global code. In a browser environment, the content of a SCRIPT element is usually parsed as a program and therefore executed as global code.

2. Of course, any code that is directly executed in a function is considered a function code. In a browser environment, the content of the event attribute (e.g.

3. Finally, the code placed in the built-in function eval is parsed as Eval code. We will soon see why this type is special.

1.2. Code execution context | Execution Context
When ECMAScript code is executed, it always occurs in a certain execution context (context). An execution scope is an abstract entity that helps understand how scopes and variable instantiation work. The above three types of executable code have their own execution context. When the function code is executed, we say that the control end enters the execution context of the function code; when the global code is executed, we say that the control end enters the execution context of the global code, and so on.

As you can see, the execution context is logically a stack. First, there may be a piece of global code, which has its own execution context; a function may be called in this code, and this function also has its own execution context; this function may call another function, and so on. Even when a function calls itself recursively, a different execution context is entered at each call.

1.3. Activation object and variable object | Activation object / Variable object
Each execution context has a variable object (Variable object) associated with it. Similarly, a variable object is an abstract entity, a mechanism used to describe variable instantiation. What's interesting is that variables and functions declared in a piece of source code are actually added to the variable object as properties of the variable object.

When control enters the execution context of global code, a global object is used as a variable object. This is precisely why globally declared variables and functions become properties of a global object:

Copy code The code is as follows:

var GLOBAL_OBJECT = this;
var foo = 1;
GLOBAL_OBJECT.foo; // 1
function bar() {};
typeof GLOBAL_OBJECT.bar; / / "function"
GLOBAL_OBJECT.bar === bar; // true

Ok, so global variables become attributes of the global function, but what about local variables - those variables declared in function code? In fact it's quite simple: they also become properties of the variable object. The only difference is that in the function code, the variable object is not a global object, but what we call an activation object. An activation object is created each time the execution context of function code is entered.

Not only the variables and functions declared in the function code become attributes of the activation object: each actual parameter of the function (arguments, with the name of the corresponding formal parameter as the attribute name), and a special Arguments object (with arguments as the attribute name) also becomes an attribute of the activated object. It should be noted that the activation object is an internal mechanism that cannot actually be accessed by program code.

Copy code The code is as follows:

(function(foo) {
var bar = 2;
function baz() {};
/*
In the process of abstraction,
special' The arguments' object becomes a property of the activation object of the function:
ACTIVATION_OBJECT.arguments = arguments;
...The same goes for the parameter 'foo':
ACTIVATION_OBJECT.foo; // 1
. ..The variable 'bar' is the same:
ACTIVATION_OBJECT.bar; // 2
  ...The function 'baz' is the same:
typeof ACTIVATION_OBJECT.baz; // "function"
*/
}) (1);

Finally, the variables declared in the Eval code become attributes of the context's Variable object. Eval code simply uses the variable object of the execution context in its call.

Copy code The code is as follows:

var GLOBAL_OBJECT = this;
eval('var foo = 1');
GLOBAL_OBJECT.foo; // 1;

(function() {
eval('var bar = 2');

/*
During the abstraction process
ACTIVATION_OBJECT.bar; // 2
*/
}) ();

1.4. Internal attributes of attributes | Property attributes
is close to the topic. Now that we know what happens to variables (they become properties), the remaining concept to understand is the internal properties of properties (property attributes). Each property has zero to more internal properties - *ReadOnly, DontEnum, DontDelete and Internal**. You can think of them as tags - a property may or may not have a special internal property. For today's discussion, we're interested in DontDelete.

When variables and functions are declared, they become properties of the Variable object—either the activation object (in function code) or the global object (in global code). These properties are accompanied by The internal property DontDelete is generated. However, any explicitly/implicitly assigned properties do not generate a DontDelete. And this is essentially why we can delete some properties but not others.

Copy code The code is as follows:

var GLOBAL_OBJECT = this;

/* 'foo' is a property of the global object,
It is generated through variable declaration, so it has the internal property DontDelete
This is why it cannot be deleted*/
var foo = 1;
delete foo; // false
typeof foo; // "number"

/* 'bar' is a property of the global object,
It is generated through variable declaration, so it has a DontDelete child
This is why it cannot be deleted either*/
function bar() { };
delete bar; // false
typeof bar; // "function"

/* 'baz' is also a property of the global object,
However, it is generated through property assignment, so there is no DontDelete
That's why it can be deleted*/
GLOBAL_OBJECT.baz = " baz";
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"

1.5, built-ins and DontDelete | Build-ins and DontDelete

So this is why all this happens: a special internal property of a property controls whether or not the property can be deleted. Note: Some properties of built-in objects have the internal property DontDelete and therefore cannot be deleted; special arguments variables (as we know, properties of activated objects) have DontDelete; the length (return parameter length) property of any function instance also Has DontDelete:

Copy code The code is as follows:

(function() {
//Cannot be deleted 'arguments', because there is DontDelete
delete arguments; // false;
typeof arguments; // "object"

//The length of the function cannot be deleted because there is DontDelete
function f() {};
delete f.length; // false;
typeof f.length; // "number"
}) ();

The properties associated with function arguments also have DontDelete and cannot be deleted either

Copy code The code is as follows:

(function(foo,bar) {
delete foo; // false
foo; // 1

delete bar; // false
bar; // "bah"
}) (1,"bah");

1.6. Undeclared variable assignments | Undeclared assignments
You may remember that undeclared variable assignments become attributes of the global object unless this attribute is found elsewhere in the scope chain. And now we understand the difference between property assignment and variable declaration - the latter generates DontDelete and the former does not - which is why undeclared variable assignments can be deleted.

Copy code The code is as follows:

var GLOBAL_OBJECT = this;

/* Generate global object attributes through variable declaration, with DontDelete */
var foo = 1;

/* Generate global object properties through undeclared variable assignment, no DontDelete */
bar = 2;

delete foo; // false
delete bar; // true
Note: Internal properties are determined when the properties are generated, and subsequent assignment processes will not change the internal properties of existing properties. It's important to understand this distinction.

/* DontDelete is generated when 'foo' is created */
function foo() {};

/* The subsequent assignment process does not change the internal attributes of the existing attributes, DontDelete still exists*/
foo = 1;
delete foo; // false;
typeof foo; // "number "

/* But when assigning a property that does not exist, a property with no internal properties is created, so there is no DontDelete */
this.bar = 1;
delete bar; // true;
typeof bar; // "undefined"

2. Firebug confusion | Firebug confusion

So, what’s going on in firebug? Why can variables declared in the console be deleted instead of as we discussed before? I said before that Eval code has a special behavior when it handles variable declarations: variables declared in Eval code actually generate a property without DontDelete.

Copy code The code is as follows:

eval('var foo = 1;');
foo; // 1
delete foo; // true
typeof foo; // "undefined"

The same is true in the function code:

Copy the code The code is as follows:

(function () {
eval('var foo = 1;');
foo; // 1
delete foo; // true
typeof foo; // "undefined"
}) ();

And this is the reason for the unexpected behavior in Firebug. All debugging text in the console appears to be compiled and executed in Eval code, rather than in global or function code. Obviously, the variable declarations eventually generate attributes without DontDelete, so they can be deleted. So be careful about the difference between normal global code and code in the Firebug console.

2.1. Delete variables via eval | Delete variables via eval
This interesting eval behavior, combined with another aspect of ECMAScript, can technically allow us to delete attributes that cannot be deleted originally. This aspect is about function declarations - they can override variables of the same name in the same execution context:

Copy code The code is as follows:

function x() { };
var x ;
typeof x; // “function”

So why does a function declaration have priority and can override a variable with the same name (or in other words, the same properties of a Variable object)? ? This is because function declarations are instantiated after variable declarations, so they can be overridden.

(Translator’s note: A function declaration can only overwrite a variable with the same name that was declared but not assigned. If a value is assigned at the time of declaration (e.g. var x = 1), the process of assigning the value will be after the function is initialized, and the function declaration will be replaced by the variable instead. Covered by assignment, as follows:)

Copy code The code is as follows:

var x = 1;
function x() { };
typeof x; // "number"

The function declaration not only replaces the value of the attribute, but also replaces its internal attributes. If we declare a function via eval, this function will also replace the previous one with its own internal properties. Since the attribute generated by the variable declared in eval does not have DontDelete, instantiating this function will "theoretically" remove the existing DontDelete internal attribute of the original attribute, allowing this attribute to be deleted (of course, it will also point the value to the newly generated function).

Copy code The code is as follows:

var x = 1;
/*cannot be deleted , 'x' has DontDelete*/
delete x; // false
typeof x; // "number"

eval('function x() { }');
/* Attribute 'x' now points to function, and there should be no DontDelete */
typeof x; // "function"
delete x ; // Should be 'true';
typeof x; // Should be "undefined"

Unfortunately, this spoofing technique was unsuccessful in every browser I tried. I might be missing something here, or the behavior is so subtle that individual browsers don't notice it.

(Translator's note: The problem here may be that the override between function declaration and variable declaration is only a change in the value pointed to, while the internal attribute DontDelete is determined at the initial declaration and no longer changes, while the variables declared in eval and functions, only the parts that have not been declared in its external context can be deleted. Regarding the execution order, since eval is a function, its call is always after other variables and functions are declared in its external context, so the related internal attributes It has also been determined that only the pointer to the value is covered:)

Copy the code The code is as follows:

/* The first alert returns "undefined" because the assignment process is after the declaration process and eval execution process;
The second alert returns "false" because although the position of x declaration is after eval,
However, eval is executed after the variable is declared, so it cannot be deleted*/
eval(' ​​alert( x ); alert(delete x) ');
var x = 1;

3. Browsers compliance

Understanding how things work is important, but the actual implementation is even more important. Do browsers adhere to these standards when creating and deleting variables/properties? For the most part, yes.

I wrote a simple test unit to check the compliance of global code, function code and Eval code. The test unit also checks whether the return value of the delete operation and the attribute are deleted as expected. The return value of delete is not as important as its actual result. It does not matter whether the delete operation returns true or false. What matters is whether the property with or without DontDelete was deleted.

Modern browsers generally abide by the deletion rules. The following browsers have all passed the test: Opera 7.54, Firefox 1.0, Safari 3.1.2, Chrome 4.

Safari 2.x and 3.0.4 have an issue with deleting function arguments, it seems that these properties are created without DontDelete and therefore can be deleted. Safari 2.x has other problems - it throws an error when deleting without a reference (such as delete 1) (Translator's note: IE also has this); function declarations generate deletable attributes (strangely, variable declarations work fine); Variable declarations in eval become undeletable (but function declarations in eval are normal).

Similar to Safari, Konqueror (3.5, not 4.3) also has the same problem with delete without references and deleting arguments.

3.1, Gecko DontDelete bug
Gecko 1.8.x browsers - Firefox 2.x, Camino 1.x, Seamonkey 1.x, etc. - have an interesting bug: explicit assignment of a value to a A property can have its DontDelete removed, even if the property was declared via a variable or function.

Copy code The code is as follows:

function foo() { };
delete foo ; // false;
typeof foo; // "function"

this.foo = 1;
delete foo; // true
typeof foo; // "undefined"

Surprisingly, IE5.5-8 also passes most of the tests, except deleting a non-reference throws an error (e.g. delete 1, just like old Safari). However, although it is not immediately obvious, IE actually has more serious bugs, and these bugs are related to global objects.

4. IE bugs

In IE (at least in IE6-8), the following expression throws an exception (in global code):

Copy code The code is as follows:

this.x = 1;
delete x; // TypeError: Object doesn't support this action

And here is another one:

Copy code The code is as follows:

var x =1;
delete this.x ; // TypeError: Cannot delete 'this.x'
// Translator's note: This exception is thrown under IE8, and the same exception as above is thrown under IE6 and 7

This seems to indicate that the variable declaration in the global code in IE does not generate the same-named property of the global object. A property created by assignment (this.x = 1) and then deleted by delete x throws an exception; a property created by variable declaration (var x = 1) and then deleted by delete this.x throws another exception (Translator's Press : The error message is the same as above under IE6 and 7).

But not only that, in fact properties created through explicit assignment always throw an exception when deleted. This is not just a bug, but the created property appears to have the DontDelete internal property, which according to the rules should not:

Copy code The code is as follows:

this.x = 1;
delete this. x; // TypeError: Object doesn't support this action
delete x; // TypeError: Object doesn't support this action

On the other hand, undeclared variable assignments (those attributes that also generate global objects) can indeed be deleted normally under IE:

Copy code The code is as follows:

x = 1;
delete x; // true

But if you try to delete via this keyword (delete this.

If we summarize, we will find that 'delete this.x' will never succeed in the global code. An exception is thrown when the attribute is generated by explicit assignment (this.x = 1); another exception is thrown when the attribute is generated by declaring/undeclaring a variable (var x = 1 or x = 1). Delete x, on the other hand, only throws an exception when the explicit assignment generates the property (this.x = 1).


In
September I discussed this issue, where

Garrett Smith
believed that in IE the global variable object (Global variable object) is implemented as a JScript object, and the global object is represented by Host object implementation.

We can run several tests to confirm this theory to some extent. Note that this and window appear to refer to the same object (if the '===' operator can be trusted), while the Variable object (the basis of the function declaration) is different from the one referenced by this .

Copy code

The code is as follows:function getBase() { return this; }; getBase() === this.getBase(); // falsethis.getBase() === this.getBase(); // true
window.getBase() === this .getBase(); // true
window.getBase() === getBase(); // false

5. Misconceptions

We cannot underestimate the importance of understanding how things work. I've seen some misunderstandings about the delete operation on the Internet. For example, An answer on Stackoverflow (and a very high ranking one) explains that "delete is supposed to be no-op when target isn't an object property". Now that we understand the core of the delete operation, it's clear that this answer is incorrect. delete does not distinguish between variables and properties (in fact these are references in the delete operation), but only cares about DontDelete (and whether the property already exists).

6. 'delete' and host object | 'delete‘ and host object

A delete algorithm is roughly like this:

1. If the operand is not a reference, return true
2. If the object does not have a **direct property** with the same name, return true (as we know, the object can be a global object or an activation Object)
3. If the property already exists but has DontDelete, return false
4. Otherwise, delete the property and return true
. However, the behavior of the delete operation on the host object may be is unpredictable. In fact, there is nothing wrong with this: the host object (through certain rules) allows any operation, such as reading (internal [[Get]] method), writing (internal [[Write]] method), deleting (internal [[Delete]] ] method), etc. Allowing custom [[Delete]] behavior leads to confusion on the host object.

We have seen some issues in IE where exceptions are thrown when deleting properties of certain objects (those implemented as host objects). Some versions of firefox throw an exception when trying to delete window.location (Translator's note: IE also throws it). Similarly, you cannot trust the return value of delete in some host objects, such as what happened in Firefox (Translator's note: the same result in Chrome; an exception is thrown in IE; Opera and Safari allow deletion, and cannot be called after deletion) , tentatively considered 'normal', although, judging from the discussion below, it seems to be abnormal. They actually delete attributes that cannot be deleted, while the previous browsers do not):

Copy code The code is as follows:

/* 'alert' is a direct property of 'window' (if we can believe 'hasOwnProperty') */
window.hasOwnProperty('alert'); // true

delete window.alert; // true
typeof window.alert; // "function"

delete window.alert returns true, although there is no condition for this property to produce this result (according to the above algorithm): It resolves to a reference, so it cannot return true in the first step; It is a direct property of the window object, Therefore, it cannot return true in the second step; the only thing that can return true is when the algorithm reaches the last step and actually deletes the attribute, but in fact it has not been deleted. (Translator's note: No, it was indeed deleted in opera and safari...).

So this story tells us never to trust the host object.

7. ES5 strict mode | ES5 strict mode

So what will strict mode bring in ECMAScript version 5? Some of these limitations are currently described. SyntaxError is thrown when a delete operation points to a direct reference to a variable/function parameter/function declaration. Additionally, if a property has an internal property [[Configurable]] == false, a TypeError will be thrown:

Copy code The code is as follows:

(function(foo) {
"use strict "; //Enable strict mode in the function

var bar;
function baz;
delete foo; // SyntaxError, when function parameters are deleted
delete bar; // SyntaxError, when variables are deleted
delete baz; // SyntaxError , when deleting a variable created by a function declaration

/* The length of the function instance has [[Configurable]]: false */
delete (function() {}).length; // TypeError
}) ();

Moreover, in strict mode, deleting an undeclared variable (in other words, an unresolved reference) will also throw a SyntaxError; similarly, an undeclared assignment in the same mode will also throw an exception (ReferenceError )

Copy code The code is as follows:

"use strict";
delete i_dont_exist; / / SyntaxError
i_dont_exist_either = 1; // ReferenceError

After looking at the examples of variables, function declarations and parameters given before, I believe you now understand that all these restrictions have their meaning. Strict mode takes a more proactive and descriptive approach rather than just ignoring these issues.

8. Summary | Summary

Since this article is already quite long, I won’t discuss other things (e.g. deleting array items via delete and its effects). You can check out the article on MDC/MDN or read the spec and test it yourself.

Here’s a quick summary of how delete works in Javascript:

•Variable and function declarations are properties of the Activation global object.
•Properties have internal properties, one of which - DontDelete - is responsible for determining whether a property can be deleted.
•Variables and function declarations in global code or function code generate attributes with DontDelete.
•Function parameters are also attributes of the activation object and also have DontDelete.
•Variable and function declarations in Eval code generate attributes without DontDelete.
• New undeclared properties are generated with empty internal properties and therefore no DontDelete.
•Host objects are allowed to respond to the deletion process in any way they desire.

Original text: Understanding deleteTranslation: delete in javascriptTranslator: justjavac

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn