Having the code:
foo = {};
foo.bar = 78;
foo.bar.baz = null;
testing foo.bar.baz against null:
if( foo.bar.baz === null )
console.log("foo.bar.baz is null");
else
console.log("foo.bar.baz is NOT null");
results in "foo.bar.baz is NOT null". Why isn't it null since i set it up explicitly?
Because primitives don't have properties, and the value in foo.bar is a primitive.
When you access (get or set) a property on a primitive, the JavaScript engine creates an object for that primitive, sets or retrieves the property value (if any), and then throws away the object. (That's why (42).toString() works; the primitive is promoted to an object backed by Number.prototype, toString is retrieved from that object and called with this referring to the object, and then the object is thrown away.)
So although an object was created in your foo.bar.baz = null statement, and its baz property was set to null, that object was never stored anywhere (certainly not in foo.bar), and so it got thrown away. Later when you do if (foo.bar.baz === null), a new object, which doesn't have the property, is created and you get undefined for its baz property (because it doesn't have one). (Naturally, JavaScript engines can optimize this process to avoid unnecessary object creation.)
We could create a function on Number.prototype that returned the object that gets created, to demonstrate that the object creation really does happen each time you access a property on a primitive:
// Add a `nifty` method to numbers
Object.defineProperty(
Number.prototype,
"nifty",
{
value: function() {
console.log("Number#nifty called");
return this;
}
}
);
var n = 42; // A primitive number
console.log(typeof n); // "number"
var obj1 = n.nifty(); // Creates an object, which we keep
console.log(typeof obj1); // "object"
var obj2 = n.nifty(); // Do it again, and a new object is created
console.log(obj1 === obj2); // false, they're not the same object
If you want to set properties on a number and keep them, you can do that by explicitly creating a Number object:
var n = new Number(42);
n.baz = null;
console.log(n.baz === null); // true
It's rare to want to do that, but it's possible. Just beware that as we showed earlier, two Number objects with the same raw value are not == to each other:
var n1 = new Number(42);
var n2 = new Number(42);
console.log(n1 == n2); // false
console.log(n1 === n2); // false
>, <, >=, and <= will coerce the number back to a primitive and use the raw value, but == and === will not.
Working with numeric value as object in strict mode will run into exception.
By default foo.bar.baz = null will be undefined because foo.bar is not object and .baz will not be set.
This is Your code in strict mode:
'use strict';
var foo = {};
foo.bar = 78;
foo.bar.baz = null;
if(foo.bar.baz === null )
alert("foo.bar.baz is null");
else
alert("foo.bar.baz is NOT null");
here is solution:
'use strict';
var foo = {};
foo.bar = {};
foo.bar.num = 78; // your number here
foo.bar.baz = null;
if( foo.bar.baz === null )
alert("foo.bar.baz is null");
else
alert("foo.bar.baz is NOT null");
p.s. always put 'use strict' inside Your JS files to be able to make JS less versatile.
This is because
foo = {};
foo.bar = 78;
foo.bar.baz = null;
console.log(foo.bar.baz); // undefined
since you are trying to set a property of a number.
foo.bar is a number primitive, not an object. You can't set properties on a number primitive, but you can set properties on a number object.
foo = {};
foo.bar = new Number(78);
foo.bar.baz = null;
Now foo.bar.baz == null.
Related
var b = true;
b.foo = 'whatever'; // Auto-boxing occurs?
b.foo; // undefined - why?
Can I retrieve the value of property foo now?
var b is initially set to Boolean value. to assign dot notation to a variable, it has to be a javascript Object.
if b is set as var b = {}, b.foo = 'whatever'; should work.
For better practice always check type of variable before switching its datatype:
var b = true;
if(typeof b === 'object'){
b.foo = 'whatever';
}
Sorry, I have a weird question; I know undefined is a type in JavaScript; is it possible to set the type of a variable to undefined?
This is a serious question for me although it seems weird.
It can be done in several ways:
Just declare a symbol:
var symbol;
Or declare a symbol and set it to undefined:
var symbol = undefined;
In case the undefined symbol was overridden:
var symbol = void 0;
Or
var symbol = (function(arg) { return arg; })();
Say your variable is named test:
delete test; // true
typeof(test); // "undefined"
This may not work with the strictest of linters or JavaScript runtime environments. This only works if the variable is in the global scope.
Accoding MDN documentation:
The global undefined property represents the primitive value undefined. It is one of JavaScript's primitive types.
Property attributes of undefined
Writable NO
Enumerable NO
Configurable NO
Ways to declare an undefined variable:
var foo;
var bar = undefined;
var baz = void 0;
var undefined = 2; // <= NO
console.log(foo); //undefined
console.log(bar); //undefined
console.log(baz); //undefined
console.log(undefined); //undefined
Mysteriously. Before you could declare the value to undefined, but now I try, and you can not. I guess now it is a reserved word.
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.
I created a popup function and recently changed the format from this:
createPopUp('My Popup',600,200);
to this method:
createPopUp({ title: 'My Popup', width: 600, height: 200 });
I only want to use the values if they exist, so I am currently doing this:
function createPopUp(config){
if (typeof config.title != 'undefined'){
var theTitle = title;
} else {
var theTitle = 'Untitled';
}
}
However this seems very messy so I have been looking for a more efficient way of checking for incoming parameters or setting default values and a nudge in the right direction would be much appreciated.
You can extend a default set of properties like this:
var defaults = {
title: 'Untitled',
width: 100,
height: 100
}
function createPopUp(config)
{
var opts = {}
for (var k in defaults) {
opts[k] = config[k] || defaults[k];
// sometimes falsy values should be allowed to override defaults
// in that case, use this instead:
// opts[k] = typeof config[k] != 'undefined' ? config[k] : defaults[k]
}
// opts contains values from defaults where config doesn't have them
}
jQuery has a handy $.extend() for this purpose, but you didn't tag your post as such.
Generally, the logical or operator is used for this:
var theTitle = config.title || 'Untitled';
Basically, the right-hand operand is an expression that will -like all expressions- resolve to a definite value. It's processedd from left to right, so if config.title is undefined, the string 'Untitled' will be the resulting value.
You can chain logical operators if you need to, too:
var someVar = obj.val || anotherObject.val || yetAnother.foo || 'bar';
Or, if all operands are objects, and you don't know which one exists:
var foo = (bar || foobar || {property: 'default: none of the objects exist').property;
The object references are grouped together, so JS will first try to resolve the variables (left to right) to an existing value, or, in the end create a new object literal with the desired propert. That reference (the result of the grouped logical-ors) is accessed, and the property .property is assigned to foo... I hope this is at least somewhat clear, if not: I'm sorry.
Caution
some properties might not be set at the instance level, or might be set, but assigned a falsy value. In that case, the logical OR is not enough, and you'll have to use either a ternary or a regular if...else:
var foo = (obj.hasOwnProperty('val') ? obj.val : 'default');//<-- uses val property, even if it's undefined, as long as it's set on the instance
//or:
var foo = 'default';
if ('val' in obj)
{//val is set, either on the instance or on its prototype-chain
foo = obj.val
}
//as ternary:
var foo = ('val' in obj ? obj.val : 'default');
var theTitle = 'Untitled';
if('title' in config && config.title != null && config.title.length > 0){
theTitle = config.title;
}
I have a basic understanding of instanceof in JavaScript, testing if the left hand side object "is of" the right hand side object type. The following 2 examples help me understand that...
var demo1 = function() {};
demo1.prototype = {
foo: "hello"
};
var demo2 = function() {
var pub = {
bar:"world"
};
return this.pub;
};
var obj1 = new demo1();
var obj2 = new demo2();
console.log(obj1 instanceof demo1); //returns true
console.log(obj2 instanceof demo2); //returns true
But on this 3rd example, I get false and I don't understand why....
var o = {}; // new Object;
o.toString(); // [object Object]
console.log(o instanceof toString); //returns false
Thanks for any help in understanding whats going on. Also...is is possible to make the 3rd example true?
Thanks again
toString does not cause a type change of o. It just returns a string representation of the object, without altering it. So, o is still a simple object and no instanceof String.
var o = {}; // new Object object
var ostring = o.toString(); // "[object Object]"
typeof o; // object
typeof ostring; // string - this is a primitive value, not an object; so that
ostring instanceof String; // is false
var stringobj = new String(ostring); // new String object
typeof stringobj; // object
stringobj instanceof String; // true!
o instanceof Object; // also true!
See also MDN reference for the String constructor.
o is an object; toString is a function. They are different types in JavaScript.
alert(typeof(o)); //"object"
alert(typeof(toString)); //"function"
JavaScript makes a distinction between objects and functions. Therefore, that's why you get false returned in your example.
With an object literal like
var o = {}; // new Object;
you create an object whose prototype is Object. Testing with instanceof will not yield any useful information. The only comparison that will yield true is
o instanceof Object