Given var x, what is the best way to determine if x can have properties? Can I just do
if(x instanceof Object)
Is that sufficient to ensure that x can have properties or do I need to check for anything else? I know primitives can't have properties but is there anything else? I've been going through checking various types:
var a = false;
a.foo = "bar";
console.log(a["foo"]);
// Logs undefined
var b = "b";
b.foo = "bar";
console.log(b["foo"]);
// Logs undefined
var c = new Array(1,2,3);
c.foo = "bar";
console.log(c["foo"]);
// Logs bar
var d = new Object();
d.foo = "bar";
console.log(d["foo"]);
// Logs bar
var e = new RegExp("");
e.foo = "foo";
console.log(e["bar"]);
// Logs bar
var f = new Number(1);
f.foo = "bar";
console.log(f["foo"]);
// Logs bar
var g = function(){};
g.foo = "bar";
console.log(g["foo"]);
// Logs bar
etc..
Yes, that is sufficient. Note: String can also accept properties, which you are not checking for:
var a = new String("hello");
a.foo = "bar";
But since String instanceof Object == true you should be fine.
For fun, try this (it works, since /x/ instanceof Object == true):
var x = /hello/;
x.foo = "bar";
Another note: your instanceof check will catch this, but I want you to be aware that while normal a javascript function is an Object, a closure (function() { })() is not necessarily an Object, but it might be depending on the value it returns.
Hope that helps.
-tjw
You need to create a JavaScript object first like so:
<script>
var foo = {};
foo.bar = 'test';
console.log(foo.bar);
</script>
Vars a and b are just plain ole variables. The var foo = {}; bit is similar to a builtin object called foo and you created an instance like var bar = new foo();
Related
I'm trying to learn about objects and JavaScript.
The problem I have is, it appears as if both the following do the same thing. My research shows nothing about what (if any) differences there are but this may be because it's very hard to question this within a search box.
Within the code, I've added comments to emphasise the differences
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id = "results"></div>
<script>
"use strict";
const results = document.getElementById("results");
const Thing = function(){ /* ****** THIS */
var _x;
this.set = function(x){
_x = x;
},
this.alert = function(){
results.innerHTML += _x + "<br />";
};
};
function Other(){ /* ****** AND THIS */
var _x;
this.set = function(x){
_x = x;
},
this.alert = function(){
results.innerHTML += _x + "<br />";
};
};
const t = new Thing();
t.set("b");
t.alert();
const t2 = new Thing();
t2.set("b2");
t2.alert();
t.alert();
t2.alert();
const o = new Other();
o.set("d");
o.alert();
const o2 = new Thing();
o2.set("d2");
o2.alert();
o.alert();
o2.alert();
</script>
</body>
</html>
JSFIDDLE
What is the difference or are they both valid?
EDIT
I have seen the duplicate var functionName = function() {} vs function functionName() {}. The difference between the questions is I'm using the word new. My question is, does that actually make a difference?
The steps that new takes are (from MDN):
A new object is created, inheriting from Foo.prototype.
The constructor function Foo is called with the specified arguments, and with this bound to the newly created object. new Foo is
equivalent to new Foo(), i.e. if no argument list is specified, Foo is
called without arguments.
The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't
explicitly return an object, the object created in step 1 is used
instead. (Normally constructors don't return a value, but they can
choose to do so if they want to override the normal object creation
process.)
It doesn't matter that you used a function expression or a function declaration at that point; just that you used a function.
function Foo() {
this.hello = "world";
}
const Bar = function() {
this.fizz = "buzz";
}
const foo = new Foo();
const bar = new Bar();
console.log(foo instanceof Foo);
console.log(bar instanceof Bar);
You might find this interesting.
You can use new on regardless of function declaration or expression.
Look at the console output. New creates a new instance of the function. There doesn't appear to be any other side effect.
function funcOne() {};
var f1 = funcOne;
var f2 = funcOne;
var fx = new funcOne();
console.log(funcOne==f1); //true
console.log(f1==f2); //true
console.log(funcOne==fx); //false
const funcTwo = function(){};
var f3 = new funcTwo();
var f4 = new funcTwo();
console.log(funcTwo==f3) //false
console.log(f3==f4); //false
If you're looking for some discussion of functions as objects, I recommend this thread javascript : function and object...?
I know that an object literal can have its keys listed by using Object.keys() method. But what about an object that was created through a constructor function?
function Foo () {}
Foo.prototype.bar = 'bar';
Foo.prototype.baz = 'baz';
var foo = new Foo();
console.log(Object.keys(foo).join(', ')); // returns ''
console.log(Object.getOwnPropertyNames(foo).join(', ')); // returns ''
Object.keys will only get own enumerable properties, and getOwnPropertyNames will only get own properties (even if not enumerable). Neither of them will give you the names of properties inherited from the prototype (or its prototype, or its, ...).
If you only care about enumerable properties, see trincot's answer.
If you want all of them,¹ even if they're not enumerable, you have to loop through the prototype chain:
function getAllPropertyNames(obj) {
var result = [];
while (obj && obj !== Object.prototype) {
result.push.apply(result, Object.getOwnPropertyNames(obj));
obj = Object.getPrototypeOf(obj);
}
return result;
}
function Foo () {}
Foo.prototype.bar = 'bar';
Foo.prototype.baz = 'baz';
var foo = new Foo();
console.log(getAllPropertyNames(foo));
In that example, I stopped when we reached Object.prototype, but of course you could keep going until you hit null instead:
function getAllPropertyNames(obj) {
var result = [];
while (obj) {
result.push.apply(result, Object.getOwnPropertyNames(obj));
obj = Object.getPrototypeOf(obj);
}
return result;
}
function Foo () {}
Foo.prototype.bar = 'bar';
Foo.prototype.baz = 'baz';
var foo = new Foo();
console.log(getAllPropertyNames(foo));
¹ "If you want all of them..." Note that in the above, we haven't tried to get properties that are named by Symbols instead of strings. If we did, we'd use getOwnPropertySymbols as well as getOwnPropertyNames.
You can use a for loop:
function Foo () {}
Foo.prototype.bar = 'bar';
Foo.prototype.baz = 'baz';
var foo = new Foo();
for (var key in foo)
console.log(key, foo[key]);
Note that this has limitations. Some properties can be made non-enumerable, and will then not be included. This is for instance the case for the length property of arrays:
var a = [1, 2];
for (var key in a)
console.log(key, a[key]);
I can do something like this:
var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)
Is there a way to mutate first foo instead of creating new function?
I need it to monkey patch some dependency without recreating whole hierarchy of objects.
I need to patch a constructor function in a library, just add an alert on every call. But without juggling with prototypes
No, you can't modify the function foo refers to. You can only make foo refer to a new function that does what you want. One way to do that is to use your toString approach, but it's best to avoid that if at all possible, because the function you get as a result will not be the same as the original; the scope it has access to will be different.
Usually, you do want a proxy/wrapper, e.g.:
// The original foo
var foo = function(arg) {
return "original foo says '" + arg + "'";
};
console.log(foo("bar"));
// Let's wrap it
(function() {
var originalFoo = foo;
foo = function() {
return originalFoo.apply(this, arguments) + " plus updated foo";
};
})();
console.log(foo("bar"));
This doesn't create a hierarchy of objects or similar, it just wraps foo.
If foo is a constructor function (let's call it Foo), you'll also want to copy Foo.prototype:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());
// Let's wrap it
(function() {
var originalFoo = Foo;
Foo = function() {
var rv = originalFoo.apply(this, arguments);
this.arg += " (plus more from augmented foo)";
return rv;
};
Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());
And of course, if you need to wrap a function on Foo.prototype, you can do it just like foo in my first example:
// The original Foo
var Foo = function(arg) {
this.value = "original foo";
this.arg = arg;
};
Foo.prototype.getArg = function() {
return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());
// Let's wrap its getArg
(function() {
var originalGetArg = Foo.prototype.getArg;
Foo.prototype.getArg = function() {
return originalGetArg.apply(this, arguments) + " updated";
};
})();
console.log(f.getArg());
Note how it doesn't matter that we wrapped the prototype function after creating the f object.
I have a chain of constructors using prototype inheritance in JavaScript like so:
var Test = function(){};
var Foo = function(){};
var Bar = function(){};
var Baz = function(){};
Bar.prototype = new Baz();
Foo.prototype = new Bar();
Test.prototype = new Foo();
I want to write a function getRootConstructor() such that
getRootConstructor(Test) === Baz.
The goal was that I could do
getRootConstructor(Test).prototype = new UniversalBaseConstructor();
So I could add functionality to a constructor without breaking the prototype chain. This turns out to be very unintuitive.
If you don't set the prototype of a function, they have a circular reference such that F.prototype.constructor === F. The function you want, then, is:
function getRootConstructor(T){
return T.prototype.constructor === T ? T : getRootConstructor(T.prototype.constructor);
}
In the OP, note that:
var t = new Test();
t.constructor == Test; // false
t.constructor == Baz; // true
So the base constructor is given by t.constructor.
However, it is very common to re–set ("fix") the constructor property when building inheritance like that so that each prototype's constructor property points to the right constructor:
var Test = function(){};
var Foo = function(){};
var Bar = function(){};
var Baz = function(){};
Bar.prototype = new Baz();
Bar.prototype.consructor = Bar;
Foo.prototype = new Bar();
Foo.prototype.constructor = Foo;
Test.prototype = new Foo();
Test.prototype.constructor = Test;
which means that Brad's getRootConstructor function will not work as Constructor.prototype.constructor always points to the "real" constructor and
getRootConstructor(Test) === Test;
In this case it is also common to add a _super (or similar named) property to each prototype that points to the prototype's constructor, so the base constructor could be found that way.
Note that if Brad's function really worked, it would always return the built–in Function object, as it is the base constructor for all functions.
Can someone explain why if I add a property to foo, somehow bar also inherits that property when I do this:
var foo = bar = {};
foo.hi = 'hi';
console.log(bar); //Object {hi: "hi"}
How does this work? I'm setting properties on foo, not bar. I realized I passed the object to bar and then bar to foo, but I must be missing something here.
Integer assignment works differently and more sense (to me anyhow):
var foo = bar = 5;
foo = 4;
console.log(bar); // 5
Objects are passed by reference in JavaScript. Strings and number literals are not. In your code foo === bar, is the same object. You can simply declare the variables separately:
// Two different object instances
var foo = {};
var baz = {};
by doing foo = bar = {};, foo and bar are pointers to same object. so when you do:
foo.hi = 'hi';
It sets bar.hi also, because foo and bar point to the same object. To make it different, you should do:
var foo = {}, bar = {};
foo.hi = 'hi';