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]);
Related
What different between assigning property on Object and Object.prototype?
for example
Object.test =function(){};
and
Object.prototype.test =function(){}
The first gives Object a static method that can be invoked directly from the class, without an instance. For example:
Object.test =function(){
console.log('Object test running');
};
Object.test();
Assigning a function to the prototype, on the other hand, allows for instances to run the method:
Object.prototype.test = function() {
console.log('test running on object ', this);
};
// don't use the object constructor, this is just an example:
const obj = new Object();
obj.test();
It might make a bit more sense if you didn't use the built-in Object, which everything inherits from:
function Foo() {}
Foo.checkIfFoo = function(arg) {
return arg instanceof Foo;
};
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Here, foo.checkIfFoo is a helper function on Foo that checks if a passed object is an instance of Foo or not - no instance is required to run checkIfFoo. Functions on the prototype, on the other hand, require an instance to run:
function Foo() {
this.info = 'A Foo instance';
}
Foo.prototype.checkInfo = function() {
console.log(this.info);
};
const f = new Foo();
f.checkInfo();
Note that in ES6+, you can put a function directly on the class with the static keyword:
// roughly equivalent to the snippet with checkIfFoo above
class Foo {
static checkIfFoo(arg) {
return arg instanceof Foo;
}
}
const f = new Foo();
console.log(Foo.checkIfFoo(f));
Whereas a standard method lacks the static keyword:
// roughly equivalent to the snippet with checkInfo above
class Foo {
constructor() {
this.info = 'A Foo instance';
}
checkInfo() {
console.log(this.info);
}
}
const f = new Foo();
f.checkInfo();
I have an object that wraps some data:
function Obj1() {
var _foo = 'bar'
this.obj2 = {
'b': 'c'
}
this.method = function() {
return _foo
}
}
var obj1 = new Obj1()
Now when I call console.log(obj1); I want it to show me object obj2 content. The trick is that I need to still be able to call obj1.method and get value of _foo. How do I do that if it's even possible?
My thought was that sth like getter will be suitable, but can't figure out where and how to assign one.
As far as I understood you're trying to hide method property. To achieve this, use Object.defineProperty. Function will not be logged because enumerable property is false by default which prevents property from showing in console.log for example.
function Obj1() {
var _foo = 'bar'
this.obj2 = {
'b': 'c'
}
Object.defineProperty(this.obj2, 'method', {
value: function() {
return _foo;
}
});
return this.obj2;
}
var obj1 = new Obj1()
console.log(obj1);
console.log(obj1.method());
if i understand correctly, you can use prototype
Example
function Obj1() {
this.obj2 = {
'b': 'c'
}
}
Obj1.prototype.method = function() {
return 'bar';
}
var obj1 = new Obj1();
//prints only properties
console.log(obj1);
//prints method result
console.log(obj1.method())
Since you calling new Obj1(). The result variable var obj1 is a class object and not a function, for you to get the value of obj2 you will have to call obj1.obj2 in your console log. If you want obj1 to hold the value of obj2. Then use the following code
function Obj1() {
var obj2 = {
'b': 'c'
}
return this.obj2;
}
var obj1 = Obj1();
console.log(obj1);
This will give you the required result in the console log, but the object will no longer be a class object and will have only the value of obj2.
Sticking to your original snippet a factory looks like a good option:
function factory() {
var foo = 'bar';
var props = { b: 'c'};
var proto = {
method: function() { return foo; }
};
var obj = Object.create(proto);
Object.assign(obj, props);
return obj;
}
var obj = factory();
console.log(obj); // {b: 'c'}
console.log(obj.method()) // 'foo'
You could even pass props as an argument to get a more flexible way of spawning objects with an "unenumerable" method accessing private members.
Is there a difference between the 2 code snippets?
Since foo is a member function of obj, this would refer to obj itself (method invocation pattern).
1.
var obj = {};
obj.prop = some_property;
obj.foo = function() {
do_something_with(obj.prop);
};
2.
var obj = {};
obj.prop = some_property;
obj.foo = function() {
do_something_with(this.prop);
};
An application I was working on, kept crashing when I used approach 2.
The code was something like :
obj = {};
obj.listener = {
eventprocess : function(param) {
//some code
}
};
obj.init = function() {
this.a = library_func();
this.a.add_listener(this.listener);
};
it worked when I used approach 1.
Any ideas why?
As the resolution of obj and this is deferred until execution of the function, it's result can vary depending on whether this or/and obj has changed between definition and invocation.
For example, given two objects which are identical, except one uses this and the other uses obj in the function foo:
var objA = {};
objA.prop = "test";
objA.foo = function() {
alert(this.prop);
};
var objB = {};
objB.prop = "test";
objB.foo = function() {
alert(objB.prop);
};
... we'll see different behavior here:
var anotherObject = {
objAFoo: objA.foo,
objBFoo: objB.foo
};
anotherObject.objAFoo(); // "undefined";
anotherObject.objBFoo(); // "test";
http://jsfiddle.net/3D6xY/
Note that you can normalize this behavior by setting the value of this using call() or apply(), as pointed out in the comments:
anotherObject.objAFoo.call(objA); // "test";
http://jsfiddle.net/3D6xY/1/
However, note also that cases where this has been bound using bind() or jQuery.proxy() can hurt you here.
Is there a difference between Object.getPrototypeOf(obj) and obj.constructor.prototype? Or are these two referencing the same thing?
NO
It returns the internal [[Prototype]] value.
For example:
var o = Object.create(null);
Object.getPrototypeOf(o); // null
o.constructor.prototype; // error
var p = {};
var o = Object.create(p);
Object.getPrototypeOf(o); // p
o.constructor.prototype; // Object.prototype
o.constructor.prototype only works with objects created through new ConstructorFunction or where you have manually set the Prototype.prototype.constructor === Prototype relationship.
No. In particular, the constructor property of an object is not always set to what you would consider "correct."
An example of where getPrototypeOf works but .constructor.prototype does not:
function F() { }
F.prototype = {
foo: "bar"
};
var obj = new F();
assert.equal(obj.constructor.prototype, Object.prototype);
assert.equal(Object.getPrototypeOf(obj), F.prototype);
It also fails for typical prototypal inheritance scenarios:
// G prototypally inherits from F
function G() { }
G.prototype = Object.create(F.prototype);
// or: G.prototype = new F();
var obj2 = new G();
assert.equal(obj2.constructor.prototype, Object.prototype);
assert.equal(Object.getPrototypeOf(obj2), G.prototype);
assert.equal(Object.getPrototypeOf(Object.getPrototypeOf(obj2)), F.prototype);
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();