Remove the Key_ basics in the middle of JavaScript object

Source: Internet
Author: User
Tags abstract eval getbase hasownproperty

You're going to go home and farm.

Copy Code code as follows:

Delete Thisisobject[key]
Or
Delete Thisisobject.key

By the way, we'll talk about the use of delete.

A few weeks ago, I had a chance to read Stoyan Stefanov's object-oriented Javascript book. The book was highly rated on Amazon (12 reviews, 5 stars), so I was curious to see if it was a book that was so well recommended, so I started reading the chapter on the function. I appreciate the way the book explains things, and the examples are organized in a very beautiful, progressive way, and it seems that even beginners can easily grasp the knowledge. Almost immediately, however, I found an interesting misunderstanding throughout the chapter-removing functional functions. There are other errors (such as the difference between function declarations and function expressions), but we will not discuss them at this time.

The book claims:

"A function is treated as a generic variable-it can be copied to a different variable, or even deleted." The following example is appended to this explanation:

Copy Code code as follows:

var sum = function (A, b) {return a + B;}
var add = sum;
Delete Sum
True
typeof sum;
"Undefined"

Ignoring the missing semicolon, can you tell where the error is? Obviously, the error is that the operation to delete sum is not successful. The delete expression should not return true, and typeof sum should not return "undefined". It's all because it's impossible to delete variables in JavaScript. At the very least, it is impossible to declare this way.

So, what happened in this case? Is it a mistake? Or is it a special use? That's probably not the case. This piece of code is in fact the real output of the Firebug console, Stoyan must have used it as a quick test tool. It's almost as if Firebug followed some of the other delete rules. Is Firebug led to the Stoyan astray! So, what's going on here?

Before answering this question, we first need to understand how the delete operator works in javascript: What exactly can be deleted and what cannot be deleted? Today, I will try to explain the problem in detail. We'll look at Firebug's "strange" behavior and realize that it's not that strange. We will delve into what is hidden behind the scenes that declare variables, functions, assign values to attributes, and delete them. We'll look at browser compatibility and some of the most notorious bugs. We will also discuss the strict mode of ES5, and how it changes the behavior of the delete operator.

I'll swap JavaScript and ECMAScript, all of which means ECMAScript (unless you're obviously talking about Mozilla's JavaScript implementations)

Unsurprisingly, the interpretation of delete is scarce on the web. MDC article is probably the best source of understanding, but, unfortunately, it lacks some interesting details about the subject. Curiously, one of the forgotten things is the reason for the strange manifestations of Firebug. and MSDN reference is almost useless in these areas.

Theory

So, why are we able to delete an object's properties:

Copy Code code as follows:

var o = {x:1};
Delete o.x; True
o.x; Undefined

You cannot delete an object that is declared like this:

Copy Code code as follows:

var x = 1;
Delete x; False
X 1

or function:

Copy Code code as follows:

function X () {}
Delete x; False
typeof X; "Function"

Note: When a property cannot be deleted, the delete operator returns false only

To understand this, we first need to grasp these concepts of variable instances and attribute attributes-these concepts are unfortunately rarely mentioned in JavaScript books. I will try to review these concepts briefly in the next few paragraphs. These concepts are hard to understand! If you don't care about "why these things work this way," skip this chapter.

Type of code:

In ECMAScript, there are 3 different types of executable code: Global Code, function code, and eval code (eval codes). These types are more or less self explanatory on the name, and here's a short overview:

When a piece of source code is viewed as a program, it is executed in the global context and is considered global code. In a browser environment, the content of a script element is usually interpreted as a program and is therefore executed as a global code.

Any code that executes directly in a function is clearly considered to be a function code. In the browser, the contents of the event property (such as <p onclick= ">") are often interpreted as functional code.

Finally, the code text that is applied to the built-in function eval is interpreted as the eval code. Soon we will find out why this type is special.

Execution contexts (Execution context):

When ECMAScript code executes, it usually occurs in a specific execution context. The execution contexts are a somewhat abstract entity concept that helps to understand how scope and variable instances (Variable instantiation) work. For each of the three executable codes, there is an execution context to correspond to. When a function is executed, we say "program control enters the execution context of the function code"; When a piece of global code is executed, the program control enters the execution context of the global Code, and so on.

As you can see, the execution context could logically constitute a stack. First, there might be a piece of global code and its own execution context, and then the code might call a function with its execution context (function). This function can call another function, and so on. Even if a function is called recursively, it is entered into a new execution context each time it is invoked.

Active object (Activation object)/variable objects (Variable object):

Each execution context has a so-called variable object (Variable object) associated with it. Similar to the execution context, a variable object is an abstract entity, a mechanism used to describe a variable instance. Interestingly, variables and functions declared in the source code are usually added to the variable object as attributes (properties).

When the program control enters the execution context of the global Code, a global object is used as a variable object. This is why a function variable declared as global can become the cause of a global object property.

Copy Code code as follows:

/* Remember that "this" refers to the global object in global scope */
var global_object = this;

var foo = 1;
Global_object.foo; 1
foo = = Global_object.foo; True

function bar () {}
typeof Global_object.bar; "Function"
Global_object.bar = = Bar; True

OK, so the global variable becomes the property of the global object, but what happens to local variables (those that are defined in the function code)? In fact, they behave similarly: they become properties of variable objects (Variable object). The only difference is that, when in function code, a variable object is not a global object, but a so-called active object (activation object). The active object is created each time it enters the execution context of the function code.

Not only the variables and functions declared in the function code will become the properties of the active object; This also occurs on each function parameter (corresponding to the name of the corresponding formal argument) and a special arguments object (named arguments). Note that the active object is an internal description mechanism that cannot be accessed in the program code.

Copy Code code as follows:

(function (foo) {
var bar = 2;
function Baz () {}
/*
In abstract terms,
Special ' Arguments ' object becomes a property of containing function ' s activation object:
activation_object.arguments; Arguments Object
... as-as-argument ' foo ':
Activation_object.foo; 1
... as-as-variable ' bar ':
Activation_object.bar; 2
-As-as-function declared locally:
typeof Activation_object.baz; "Function"
*/
}) (1);

Finally, the variable declared in the eval code becomes the property of the variable object of the caller context (calling). The eval code simply uses the variable object in the execution context of the code that invokes it.

Copy Code code as follows:

var global_object = this;
/* ' foo ' is created as a-calling context Variable object,
Which in the case is a Global object * *
Eval (' var foo = 1; ');
Global_object.foo; 1
(function () {
/* ' Bar ' is created as a-calling context Variable object,
Which in the case being an activation object of containing function */
Eval (' var bar = 1; ');
/*
In abstract terms,
Activation_object.bar; 1
*/
})();

Attribute (property attributes)

We're almost already here. Now that we know exactly what is happening on the variables (they become attributes), the only other concept that needs to be understood is the attributes (property attributes). Each attribute can have 0 or more attributes, which are selected from the following collection: ReadOnly, Dontenum, Dontdelete and Internal. You can think of them as flags--. An attribute can exist in a property, or it may not exist. For our discussion today, we are only interested in dontdelete.

When the declared variables and functions become properties of variable objects (or the active object of the function code, or global object of global Code), these properties are created with the Dontdelete attribute. However, any explicit (or implicit) property assignment of an attribute will not be brought up with the Dontdelete attribute. That's why we can delete some attributes, but not the other.

Copy Code code as follows:

var global_object = this;
/* ' foo ' is a property of a Global object.
It is created via variable declaration and so has dontdelete attribute.
This is why it can deleted. */
var foo = 1;
Delete foo; False
typeof Foo; "Number"
/* ' Bar ' is a property of a Global object.
It is created via function declaration and so has dontdelete attribute.
This is why it can deleted either. */
function bar () {}
Delete bar; False
typeof Bar; "Function"
/* ' Baz ' is also a property of a Global object.
However, it is created via the assignment and so has no dontdelete attribute.
This is why it can be deleted. */
Global_object.baz = ' blah ';
Delete Global_object.baz; True
typeof Global_object.baz; "Undefined"

Built-in objects and Dontdelete

So, this is a special feature of all of its properties, which controls whether this property can be deleted or not. Dontdelete Note that some of the built-in objects ' properties are specified to contain dontdelete, so they cannot be deleted. such as a special arguments variable (or, as we now know, an active object's properties) has dontdelete. The length property of a function instance also has the Dontdelete property.

Copy Code code as follows:

(function () {
/* can ' t delete ' arguments ', since it has dontdelete * *
Delete arguments; False
typeof arguments; "Object"
/* can ' t delete function ' s ' length '; It also has dontdelete * *
function f () {}
Delete f.length; False
typeof F.length; "Number"
})();

The property corresponding to the function parameter also has the Dontdelete attribute from the beginning, so we can't delete it either.

Copy Code code as follows:

(Function (foo, bar) {
Delete foo; False
Foo 1
Delete bar; False
Bar ' Blah '
}) (1, ' blah ');

Unassigned Assignment:

You may also remember that an undeclared assignment creates an attribute on the global object, unless the attribute is already found elsewhere in the scope chain before the global object. And now we know the difference between a property assignment and a variable declaration-the latter sets the Dontdelete property, but the former does not. We must understand why undeclared assignments create a property that can be deleted.

Copy Code code as follows:

var global_object = this;
/* Create global property via variable declaration; Property has Dontdelete * *
var foo = 1;
/* Create global property via undeclared assignment; Property has no Dontdelete * *
bar = 2;
Delete foo; False
typeof Foo; "Number"
Delete bar; True
typeof Bar; "Undefined"

Note that attributes are determined when a property is created, and subsequent assignments do not modify attributes that already exist. It is very important to understand this distinction.

Copy Code code as follows:

/* ' foo ' is created as a and dontdelete * *
function foo () {}
/* Later assignments does not modify attributes. Dontdelete is still there! */
foo = 1;
Delete foo; False
typeof Foo; "Number"
/* But assigning to a property that doesn ' t exist,
Creates that property with empty attributes (and so without dontdelete) * *
This.bar = 1;
Delete bar; True
typeof Bar; "Undefined"

Firebug's Confusion:

What happened in the Firebug? Why is it that the variables declared in the console can be deleted, not contrary to the knowledge we have learned before? Well, as I said earlier, the Eval code has a special performance in the face of variable declarations. The variable declared in eval is actually created as an attribute with no dontdelete attribute.

Copy Code code as follows:

Eval (' var foo = 1; ');
Foo 1
Delete foo; True
typeof Foo; "Undefined"

Similarly, when called in the function code:

Copy Code code as follows:

(function () {

Eval (' var foo = 1; ');
Foo 1
Delete foo; True
typeof Foo; "Undefined"

})();

This is the basis of firebug abnormal behavior. All text in the console is parsed and executed as an eval code, not global or function code. Obviously, all the variables declared here will eventually become properties without the Dontdelete attribute, so they can all be easily deleted. We need to know the difference between the global code and the Firebug console.

To delete a variable by eval:

This interesting eval behavior, plus another aspect of ECMAScript, can technically allow us to remove the "non-deletable" attribute. The point about function declarations is that they can overwrite variables with the same name in the same execution context.

Copy Code code as follows:

function X () {}
var x;
typeof X; "Function"

Note how a function declaration obtains precedence and overwrites a variable of the same name (or, in other words, the same attribute in a variable object). This is because function declarations are instantiated after the variable declaration and are allowed to overwrite them (variable declarations). A function declaration replaces not only the value of an attribute, but also the attribute of that property. If we declare a function through eval, that function should replace the attributes of the original (substituted) attribute with its own attributes. Also, because a variable declared through eval creates an attribute without the Dontdelete attribute, instantiating the new function will actually remove the existing Dontdelete attribute from the attribute, so that a property can be deleted (and obviously point its value to the newly created function).

Copy Code code as follows:

var x = 1;
/* Can ' t Delete, ' x ' has dontdelete * *
Delete x; False
typeof X; "Number"
Eval (' function X () {} ');
/* ' X ' property now references function, and should have no dontdelete * *
typeof X; "Function"
Delete x; Should be ' true '
typeof X; should be "undefined"

Unfortunately, this "deception" does not work in any of the current implementations. Maybe I'm missing something here, or the behavior is just too obscure for the implementation to notice.

Browser compatibility:

It is useful to understand theoretically how things work, but practice is the most important. is the browser compliant when faced with the creation/deletion of variables/attributes? The answer is: In most cases, yes.

I wrote a simple test set to test the browser's compatibility with the delete operator, including the tests under Global Code, function code, and eval code. The test set checks whether the return value of the delete operator and the property value (as they should behave) are really deleted. The return value of the delete is not as important as its true result. If Delete returns true instead of false, this is not really important, and it is important that the attributes that have the Dontdelete attribute are not deleted and vice versa.

Modern browsers are generally quite compatible. Except for the eval features I mentioned earlier, the following browsers passed all the test sets: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+.

Safari 2.x and 3.0.4 have problems deleting function parameters; These properties appear to be created without dontdelete, so you can delete them. Safari 2.x has more problems--deleting unreferenced type variables (such as: Delete 1) throws an exception; A function declaration creates a property that can be deleted (but, strangely, the variable declaration does not); Variable declarations in eval become not removable (but function declarations can be deleted).

Like Safari, Konqueror (3.5, not 4.3) throws an exception when the unreferenced type is deleted (for example, delete 1) and incorrectly makes the function variable removable.

Translator Note:

I tested the latest version of Chrome and Firefox as well as IE, and basically kept the fail other pass in addition to 23,24. At the same time, the test of UC and some mobile browsers, in addition to Nokia E72 's own browser will also fail 15,16, the rest of the browser is mostly the same as the desktop browser effect. But it is worth mentioning that the Blackberry Curve 8310/8900 's own browser can pass test 23, I am very surprised.

Gecko Dontdelete Bugs:

Gecko 1.8.x Browser--firefox 2.x, Camino 1.x, SeaMonkey 1.x and so on. --A very interesting bug, the explicit assignment of a property deletes its dontdelete attribute, even if it is created by a variable declaration or function declaration.

Copy Code code as follows:

function foo () {}
Delete foo; False (as expected)
typeof Foo; "Function" (as expected)
* Now assign-a property explicitly * *
This.foo = 1; erroneously clears Dontdelete attribute
Delete foo; True
typeof Foo; "Undefined"
/* Note "This" doesn ' t happen when the assigning property implicitly * *
function bar () {}
bar = 1;
Delete bar; False
typeof Bar; "Number" (although assignment replaced property)

Surprisingly, Internet Explorer 5.5-8 has passed a complete test set that throws an exception (like Old Safari) except to delete a unreferenced type (such as: Delete 1). But under IE there is more serious bugs, it is not so obvious. These bugs are related to global object.

IE Bugs:

This whole chapter is about Internet Explorer's bugs? Wow! It's amazing!

In IE (ie 6-8 at least), the following expression throws an exception (when executed in global code):

this.x = 1;
Delete x; Typeerror:object doesn ' t support this action
This one will also, but it will throw a different exception, which makes things more interesting:

var x = 1;
Delete this.x; Typeerror:cannot Delete ' this.x '
It looks like it's in IE, the variable declaration in global code does not create a property on the global object. By assigning values to create a property (This.x = 1) and then deleting it via delete x throws an error. Creating a property by declaration (var x = 1) and then deleting it via the delete this.x will throw another error.

But that's not all. Creating a property by an explicit assignment actually always causes an exception to be thrown at the time of deletion. There are more than just bugs, and the attributes you create seem to have dontdelete attributes, which of course should not.

this.x = 1;

Delete this.x; Typeerror:object doesn ' t support this action
typeof X; "Number" (still exists, wasn ' t deleted as it should have)

Delete x; Typeerror:object doesn ' t support this action
typeof X; "Number" (wasn ' t deleted again)
Now we think that under IE, undeclared assignments (should create properties on global objects) do create properties that can be deleted.

x = 1;
Delete x; True
typeof X; "Undefined"
However, if you are using the this citation in global code to delete this attribute (delete this.x), a similar error pops up.

x = 1;
Delete this.x; Typeerror:cannot Delete ' this.x '
If we want to generalize about this behavior, it seems that it is never possible to delete a variable from the global code using the delete this.x. The delete throws an error when the property in the problem is created by an explicit assignment (this.x = 1); When a property is created from an undeclared assignment (x = 1) or through a declaration (var x = 1), the delete throws another error.

Delete x, on the other hand, should throw an error only when the property is created by an explicit assignment--this.x = 1. If a property is created by declaration (var x = 1), the delete operation never occurs and the deletion returns false correctly. If an attribute is created by an undeclared assignment (x = 1), the deletion will work as expected.

I thought about this September again, Garrett Smith suggested that under IE,

"Global variable objects (the global variable object) are implemented as a JScript object, and global objects are implemented by host."

Garrett used Eric Lippert ' s blog entry as a reference.

We can confirm this theory by implementing some tests. Note that this and window should appear to point to the same object (if we can trust the = = = operator), but the variable object (the object where the function declaration is) is different from this point.

Copy Code code as follows:

/* in Global code */
function GetBase () {return this;}

GetBase () = = = This.getbase (); False
This.getbase () = = = This.getbase (); True
Window.getbase () = = = This.getbase (); True
Window.getbase () = = = GetBase (); False

Misunderstanding:

The beauty of understanding why things work in that way is not to be underestimated. I've seen some misunderstandings about the delete operator on the web. For example, the answer to this stackoverflow (with its surprisingly high rating) explains confidently

"Delete should be no action when the target operand is not an object property."

Now that we have understood the core of the delete action, the error of the answer becomes apparent. Delete does not differentiate between variables and attributes (in fact, they are all reference types for delete) and is in fact concerned only with Dontdelete attributes (and the existence of the property itself).

It's also very interesting to see all kinds of misunderstandings contradict each other, in a same topic, one person first suggests that only the delete variable (which will not work unless it is declared in eval), while the other person provides a false correction stating how delete is used in global code to delete a variable. But not in the function code.

Be cautious about the interpretation of JavaScript on the web, and the ideal approach is to always understand the nature of the problem. ;)

Delete and Host objects (host object):

The algorithm for delete is probably this:

Returns true if the operand is not a reference type
Returns true if the object does not have a direct attribute of this name (as we know, the object can be an active object or a global object)
Returns false if the attribute exists but has a dontdelete attribute
In other cases, delete the property and return True
However, the behavior of the delete operator on the host object is unpredictable. And this behavior is actually not wrong: (according to the criteria), the host object is allowed to implement any behavior for several of the operators, such as read (the internal [[]] method), write (internal [put] method), and Delete (internal [[Delete]] method). This grace of custom [[Delete]] behavior is why the host object becomes so confusing.

We've seen some of the quirks of IE, and deleting a particular object (apparently the one being implemented as a host object) throws an error. Some versions of Firefox will be thrown when the window.location is deleted. When the operand is the host object, you cannot trust the return value of the delete. Let's take a look at what's going on in Firefox:

Copy Code code as follows:

/* "Alert" is a direct property ' window ' (if we were to believe ' hasownproperty ') * *
Window.hasownproperty (' alert '); True

Delete Window.alert; True
typeof Window.alert; "Function"

The delete Window.alert returns true, even though this attribute has absolutely no reason to cause such a result. It resolves to a reference (so it does not return true in the first step). This is a direct property of a Window object (so it will not return true in the second step). So delete the only thing that can return true is to get to step fourth and actually delete that attribute. However, this property has never been deleted.

The moral of the story is: Never trust the host object.

ES5 Strict mode:

So, what does strict model ECMASCRIPT5 bring to us? It introduces a few limitations. When the delete operator's expression is a direct reference to a variable, a function argument or a function identifier, the syntax error is thrown. Also, if the property has an internal attribute [[[configurable]] = = False, a type error will be thrown.

Copy Code code as follows:

(function (foo) {
"Use strict"; Enable strict mode within this function
var bar;
function Baz () {}
Delete foo; SyntaxError (when deleting argument)
Delete bar; SyntaxError (when deleting variable)
Delete Baz; SyntaxError (when deleting variable created with function declaration)
/* ' length ' of function instances has {[[configurable]]: false} */
Delete (function () {}). length; TypeError
})();

In addition, deleting an undeclared variable (or an unresolved reference) will also throw a syntax error:

"Use strict";
Delete i_dont_exist; SyntaxError
An undeclared assignment is similar to the behavior of an undeclared variable in strict mode (except this time by raising a reference error instead of a syntax error):

"Use strict";
I_dont_exist = 1; Referenceerror
As you can now see, all limitations are more or less justified, because the deletion of variables, function declarations and parameters can cause so much confusion. Rather than silently ignoring deletion, the strict model employs a more aggressive and descriptive approach.

Summarize:

This blog post finally becomes quite long, so I'm not going to talk about it like deleting an array object with delete or what it means. You can refer to the MDC article for its specific explanations (or read the standard and do your own experiments).

Here's a short summary of how the delete operation in JavaScript works:

Variables and function declarations are properties of the active object or global object
Property has some attributes, the dontdelete of which is the attribute that determines whether this property can be deleted.
Variables and function declarations in the global or function code always create attributes with Dontdelete attributes.
Function arguments are always properties of the active object and have dontdelete.
Variables and functions declared in the Eval code always create properties that do not have dontdelete.
The new attribute is not characteristic when it is established (and of course there is no dontdelete).
The host object is allowed to decide how to respond to the delete operation.
If you want to be more familiar with what is described here, please refer to ECMA-262 3rd edition specification.

I hope you can enjoy this article and learn something new. Please ask any questions, suggestions or corrections.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.