function foo(){}
delete foo.length;
alert(typeof foo.length);
// result is number
Why the above code alert number? Is this a bug?
-Nick
Thank you!
A function object has a built-in property named .length that specifies the number of arguments that were defined with the function which is something you can't delete or change its value.
The length property specifies the number of arguments expected by the function. And it has property attributes Writable: false, Enumerable: false, Configurable: true. So you can't delete that. It always returns a number.
2018 Update
Actually, it is even stranger than your example demonstrates.
Using this code it seems that the foo.length cannot be changed:
function foo() {}
alert(foo.length); // alerts 0
delete foo.length;
alert(typeof foo.length); // alerts 'number'
alert(foo.length); // alerts 0
But this is more interesting:
function foo(a, b, c) {}
alert(foo.length); // alerts 3
delete foo.length;
alert(typeof foo.length); // alerts 'number'
alert(foo.length); // alerts 0
So it's not that your delete foo.length doesn't change the value - it does, but it changes it to 0!
It's worth noting that this has no effect in non-strict mode:
foo.length = 0;
foo.length++;
But both of the above lines will raise an exception in strict mode:
TypeError: Cannot assign to read only property 'length' of function 'function foo(a, b, c) {}'
But delete foo.length works also in the strict mode, always changing the foo.length to zero.
delete foo.length does not work because length still exist in function prototype and it is 0.
To change function length or name you can redefine it as writable.
Object.defineProperty(foo, 'length', { writable: true, configurable: true });
Now you can change length.
Remember if you delete length you'll still have 0 from function prototype.
You can change it if you want:
Object.setPrototypeOf(foo, {});
Function still be usable.
Related
This question already has answers here:
delete a.x vs a.x = undefined
(9 answers)
Closed 5 years ago.
I want to set the property of object to something if condition is true, else do nothing.
And I tried to use ? operator by
obj.prop = (...)?sth:null;
and
obj.prop = (...)?sth:undefined;
But it turns out that nether one of them can perform what I want.
Given the condition is false, when I called obj.hasOwnProperty(prop), it always gives me true.
Is there a way to do it?
I know I can do it by using if syntax but I just want to know if I can do the same thing using ? operator.
When you assign a property like this:
var obj = {
a : undefined // or any other value
};
this happens according to the ECMAScript spec:
11.1.5 Object Initialiser
[...]
The production PropertyNameAndValueList : PropertyAssignment is evaluated as follows:
Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
Let propId be the result of evaluating PropertyAssignment.
Call the [[DefineOwnProperty]] internal method of obj with arguments propId.name, propId.descriptor, and false.
Return obj.
When you assign a property like this:
obj.a = undefined;
this happens according to the ECMAScript spec:
8.12.5 [[Put]] ( P, V, Throw )
[...]
Else, create a named data property named P on object O as follows
a. Let newDesc be the Property Descriptor
{[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}.
b. Call the [[DefineOwnProperty]] internal method of O passing P, newDesc, and Throw as arguments.
In either case, since undefined and null are legimite values, this will just define the property with this value.
Finally, hasOwnProperty() will only check if a property descriptor was created, the value does not matter:
15.2.4.5 Object.prototype.hasOwnProperty (V)
[...]
Let desc be the result of calling the [[GetOwnProperty]] internal method of O passing P as the argument.
If desc is undefined, return false.
Return true.
But, according to the ECMAScript spec, both a property set to undefined and a not set property, will return undefined if you access them:
8.12.3 [[Get]] (P)
[...]
If desc is undefined, return undefined.
If IsDataDescriptor(desc) is true, return desc.[[Value]].
Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
If getter is undefined, return undefined.
Return the result calling the [[Call]] internal method of getter providing O as the this value and providing no arguments.
Proof:
var obj = {
a : undefined
}
console.log(typeof obj.a); // undefined
console.log(typeof obj.b); // undefined
obj.hasOwnProperty('a') // true
obj.hasOwnProperty('b') // false
Only delete will remove the property.
var obj = {
a : null,
b : undefined
}
obj.hasOwnProperty('a') // true
obj.hasOwnProperty('b') // true
delete obj.a;
delete obj.b;
obj.hasOwnProperty('a') // false
obj.hasOwnProperty('b') // false
Reading the ECMAScript spec on delete is left to the reader.
Assuming that the result of your condition is falsy enough, something like this should work.
All falsey values in JavaScript
var obj = {
a: true,
b: false,
}
obj.prop1 = obj.a ? true : false;
obj.prop2 = obj.b ? true : false;
console.log(obj);
Please check the fiddle - http://jsfiddle.net/n8emgLw9/
var a = [3, 6, 1, "str", 8];
$.each(a, function (i, e, x) {
console.log(this);
console.log(this + " is of type " + typeof this);
});
1) It logs as a primitive value in the first log entry, and then typeof logs as an object. Something is not right or it is a misnomer.
2) logging only "this"(first log statement) gives more details, but when logged in the second statement, it just prints the value. Why?
When you use call or apply (what $.each does behind the scenes) and pass a primitive, JS implicitly "boxes" it into a corresponding object type:
function foo() {
document.write(typeof this);
document.write(Object.prototype.toString.call(this));
}
foo.apply(123)
Reference: http://ecma-international.org/ecma-262/5.1/#sec-10.4.3
<...> if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
Those are not primitives. Compare:
console.log("foo", new String("foo"));
console.log(1, new Number(1) );
console.log(true, new Boolean(true));
The first values are primitives; the second ones are objects that wrap primitives (i.e. boxed versions).
As to why it happens, $.each is implemented in terms of Function.prototype.call, which has this bit in its documentation (MDN):
The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
(Emphasis mine)
Here is updated code.
You may have expected this result than yours?
http://jsfiddle.net/n8emgLw9/1/
var a = [3, 6, 1, "str", 8];
for (var e in a){
console.log(a[e]);
console.log(a[e] + " is of type " + typeof a[e]);
}
If you use + operator, js casts the whole thing to string.
What you probably want to use is:
console.log(this, " is of type " + typeof this);
with the comma.
I want a property that would always be undefined:
var foo = {bar:undefined}
If someone later try to change property bar then also it should results in undefined.
foo.bar = 'someValue'//
foo.bar//this time this should result in undefined.
I mean how to set a property that is unchangeable.
OK, based on the hint from #somethinghere (who is breaking his/her own answer again…) here is a working example, that sets up an object member, which defaults to undefined and is not writeable:
var foo = {}
Object.defineProperty(foo, 'bar', {
enumerable: false,
configurable: false,
writable: false
});
foo.bar = 'abcdefg';
console.log( foo.bar ); // returns undefined
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Be aware that you may still remove and re-set this property. (While you can't simply overwrite it.)
You can currently do this:
var foo = {}
Object.defineProperty(foo, 'bar', {
enumerable: false,
configurable: false,
writable: false,
value: undefined
});
As some have pointed out, undefined would not equal "undefined", one obviously being a string. However, I have added it for the sake of clarity as omitting the value property really loses the point of being able to use defineProperty to make them non-configurable. Once configured, its over, so its useful to have the value. Omit value if you want it to return undefined.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
The code below defines a custom method for the Object's prototype that uses the native method "hasOwnProperty" to find the owner of the passed in property.
Object.prototype.findOwnerOfProperty = function(propName){
var currentObject = this;
while (currentObject !==null){
if (currentObject.hasOwnProperty(propName)){
return currentObject;
}
}
}
My encounters with while loops have been usually of this format:
while ( x < 10 ){
// do stuff
x++;
}
Say I called the "findOwnerOfProperty" method on an object:
newObject.findOwnerofProperty(firstProp);
My questions are:
1) What happens to the "this" object while the loop is running?
2) What exactly is the loop iterating through?
3) What is the difference between the first while loop and the second while loop, where the second loop has an obvious increment that explicitly changes the counter 'x' and the first loop doesnt? Which part of the first code changes the "currentObject"?
What is the difference between the first while loop and the second while loop
The first while loop is an infinite loop because currentObject never changes.
Property names are resolved firstly on the object itself, then on the objects on it's [[Prototype]] chain. You can access that chain using Object.getPrototypeOf, so you might be able to do something like:
Object.prototype.findOwnerOfProperty = function(propName) {
var obj = this;
do {
if (obj.hasOwnProperty(propName)) {
return obj;
}
obj = Object.getPrototypeOf(obj);
} while (obj)
}
// Some tests
var obj = {foo:'foo'};
var x = obj.findOwnerOfProperty('foo');
console.log(x == obj); // true
// Find foo on Bar.prototype
function Bar(){}
Bar.prototype.foo = 'foo';
var bar = new Bar();
var p = Object.getPrototypeOf(bar);
console.log(bar.findOwnerOfProperty('foo') == Bar.prototype); // true
// Find toString on Object.prototpye
console.log(bar.findOwnerOfProperty('toString') === Object.prototype); // true
// Non-existant property
console.log(bar.fum); // undefined
console.log(bar.findOwnerOfProperty('fum')); // undefined
The above returns undefined if no such object is found, which seems appropriate given that null is at the end of all [[Prototype]] chains and returning null would suggest that the property was found there.
Note that Object.getPrototypeOf is ES5 so not in all browsers in use.
Edit
It's possible that the function will be called with a value of this that isn't an Object, e.g.:
bar.findOwnerOfProperty.call(null, 'bar');
The desired outcome might be undefined or perhaps a type error, however the actual result depends on whether the code is strict or not and the value provided.
Non–strict code—if this is a primitive, then it will be set to the result of applying the abstract ToObject operator to the primitive value (e.g. if it's a number, then effectively new Number(value), if it's a string, then new String(value)).
In the case of null and undefined, this is set to the global object (note that applying ToObject to null or undefined throws an error) so the wrong inheritance chain will be checked (i.e. the global object, not null) and possibly the global object will be returned.
The fix for both these cases is "RTFM" (well, if there was one…) since by the time any code is executed, this has already been set and it's impossible to check the original call.
Strict code—in this case the value of this is not modified so a check can be made to ensure it's an Object or Function and return undefined otherwise:
Object.prototype.findOwnerOfProperty = function(propName) {
var obj = this;
// Only applies to strict mode
if ((typeof obj != 'object' && typeof obj != 'function') || obj === null) return;
while (obj) {
if (obj.hasOwnProperty(propName)) {
return obj;
}
obj = Object.getPrototypeOf(obj);
}
}
So there may be different results for strict and non–strict mode, e.g.
bar.findOwnerOfProperty.call(7, 'toString');
returns undefined for strict code and Number (i.e. the Number constructor) for non–strict code (because 7 is converted to a Number object as if by new Number(7), and calling typeof on a Number object returns 'object').
To achieve consistency, for values other than null and undefined, the ToObject operator could be emulated for strict code. Alternatively, the non–strict version could operate only on values where typeof returns function or object. I'll leave that decision to anyone who actually wants to implement this in anger.
What's the difference between the return values of these two expressions...
Expression 1: typeof foo['bar'] !== 'undefined'
Expression 2: 'bar' in foo
... assuming that these conditions are met:
foo is an object,
foo does not contain any properties that have the value undefined set explicitly.
The first tests the value of bar in foo.
The second tests for the existence of the bar property in foo.
var foo = {bar:undefined};
typeof foo['bar'] !== 'undefined'; // false
'bar' in foo; // true
EDIT:
To add some clarification from the comments below, the issue OP is having is that accessing the domConfig property of window.document throws an Error.
This is an issue not related to the typeof operator, but rather to a specific issue with Firefox.
The issue has been documented here as a bug (back in 2003).
A few notable comments from that report:
Zbigniew Braniecki [:gandalf] 2003-11-19 09:09:31 PST
then why it can be iterated with for-in ?
Boris Zbarsky (:bz) 2003-11-19 09:24:05 PST
Because it is defined as a property on the nsIDOM3Document interface. It's
just one that throws if you try to access its getter. ...
Zbigniew Braniecki [:gandalf] 2003-11-19 09:33:53 PST
... So what kind of bug is it?
The goal is to remove not implemented method/property from interface or to
implement it?!?
Boris Zbarsky (:bz) 2003-11-19 09:53:23 PST
The goal is to eventually implement this.
My reading of the spec suggests that they should be the same. The "in" operator semantics are defined in terms of making a call to the internal (conceptual) [[HasProperty]] method, which itself is defined in terms of [[GetProperty]]. When [[HasProperty]] returns "undefined", then the "in" operator results in boolean false; otherwise it's true. Based on the definition of what [[GetProperty]] is supposed to do, that means that an "undefined" result of a property access would have the same meaning.
Given the conditions you outline, there is no difference. Both should produce the same boolean result and should behave the same around prototype lookup.
Object.prototype.hasOwnProperty.call(null, foo, 'bar')
is another common idiom that does the same as those two but does not incude properties available only on the prototype.
var foo = {};
foo.bar = undefined;
console.log("bar" in foo); // true
console.log(typeof foo["bar"] !== "undefined"); // false
var Con = function() {};
Con.prototype.bar = undefined;
var foo = new Con;
console.log("bar" in foo); // true
console.log(typeof foo["bar"] !== "undefined"); // false
The in check is simply the same as using a for in loop and returning true if the key is in the for in loop.
[Edit] Didn't see your "don't explicity set it to undefined" condition.
var foo = {}
Object.defineProperty(foo, "bar", {
"value": 42,
"enumerable": false
});
console.log("bar" in foo); // true (in chrome & FF4)
console.log(typeof foo["bar"] !== 'undefined'); // true
I actaully expected the in test to fail if you set it as non-enumerable. Seems like they are the same.
var foo = {}
Object.defineProperty(foo, "bar", {
"value": 42,
"writable": false
});
console.log("bar" in foo); // true (in chrome & FF4)
console.log(typeof foo["bar"] !== 'undefined'); // true
Both test still work if the property is "readonly"
var foz = {}
Object.defineProperty(foz, "bar", {
"value": 42
});
var foo = Object.freeze(foz);
console.log("bar" in foo); // true (in chrome & FF4)
console.log(typeof foo["bar"] !== 'undefined'); // true
Freezing the object also doesn't break the tests.
Given those two conditions, the expressions should give you identical results, except if
foo has an EcmaScript 5 getter defined for the bar property. Since the first expression actually reads the property value, that getter will be invoked. The second expression merely checks for the existence of the property so there is no need to incoke any such getter.
you are targeting Internet Explorer 4.0 - the in operator wasn't added until JavaScript 1.4 ;)
Here's some sample code to illustrate the difference in supporting browsers (Chrome, IE9, FF4):
var foo = {};
Object.defineProperty(foo, "bar", {
"get": function () {document.write("Getter invoked!<br/>"); return foo;}
});
document.write('"bar" in foo -->' +
("bar" in foo));
document.write('<br/>');
document.write('typeof foo["bar"] !== "undefined" -->' +
(typeof foo["bar"] !== "undefined"));
document.write('<br/>');
the first one first checks existence of 'bar' key in foo (undefined is returned if it's not found), then checks the type of that key.
the second on checks only existence.