I have created the following test and I am unsure why it does not work: http://jsfiddle.net/SKphY/. I should be getting three alert dialogs: "hello" and "goodbye" and "goodbye". Instead I am only geting the first two.
var p = {
hello : function() {
alert('hello');
}
};
var obj1 = Object.create(p, {
goodbye : function() {
alert('goodbye');
}
});
var obj2 = $.extend(p, {
goodbye : function() {
alert('goodbye');
}
});
$(function() {
// The third line (below) gives the parser error:
// 'Uncaught TypeError: Property 'goodbye' of object #<Object>
// is not a function'
obj1.hello();
obj2.goodbye(); // This executes fine
obj1.goodbye(); // This gives the parser error
});
The point is I am learning how to work with object inheritance, in this case with object literals, and I am curious why it is working for me when I use jQuery.extend, but not with Object.create. From what I can tell, I seem to have followed the approach that is outlined at https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create. What am I doing wrong?
Thanks for your time,
ktm.
http://jsfiddle.net/SKphY/1/
As #headacheCoder points out, the second argument in Object.create is for properties object (this is also described in the MDN document you linked).
Check the link above for a workable solution:
var obj1 = Object.create(p, {
goodbye : {value : function() {
alert('goodbye');
}}
});
The second argument in Object.create is for a properties object, not for merging. Use var obj1 = Object.create(p); instead and it will work as expected.
If specified and not undefined, an object whose enumerable own properties (that is, those properties defined upon itself and not enumerable properties along its prototype chain) specify property descriptors to be added to the newly-created object, with the corresponding property names.
// Example where we create an object with a couple of sample properties.
// (Note that the second parameter maps keys to *property descriptors*.)
o = Object.create(Object.prototype, {
// foo is a regular "value property"
foo: { writable:true, configurable:true, value: "hello" },
// bar is a getter-and-setter (accessor) property
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) { console.log("Setting `o.bar` to", value) }
}})
Related
As you can see below is my code. I have created two objects halogen and balloon and given halogen property of sing and balloon property of read. I am calling halogen.read() it is getting read property but halogen is prototype for balloon but balloon is not prototype of halogen. How js is working under the hood??
const halogen = {
sing: function() {
console.log('I can sing');
}
}
const balloon = new Object(halogen);
balloon.read = function() {
console.log('I can read');
}
halogen.read();
When you call the Object constructor with an argument that isn't null or undefined, it doesn't create a new object (not even when you use new, surprisingly; spec link), it just converts the argument to object if it isn't already an object and returns it. Since halogen already refers to an object, there's no conversion required and you're basically doing balloon = halogen and they both end up referring to the same object.
You probably meant to use Object.create, which creates a new object and assigns the object argument you provide as the new object's prototype:
const halogen = {
sing: function() {
console.log("I can sing");
},
};
const balloon = Object.create(halogen);
balloon.read = function() {
console.log("I can read");
};
console.log(typeof halogen.read); // undefined
console.log(typeof balloon.read); // function
console.log(typeof balloon.sing); // function
For the following syntax
a = {
get p() {
alert(1)
}
};
alert(a.p);
It prompts me 1, than undefined.
For
a = {
set p(x) {
alert(x)
}
};
alert(a.p);
It prompts me undefined.
I do not totally understand the behaviour,
what does
a = {
get p() {
alert(1)
}
}
and
a = {
set p(x) {
alert(x)
}
};
mean?
There are two types of object properties: data properties and accessor properties. Accessor properties are accessed by getters and setters.
Your object a is intended as object with accessor property which called p.
Normally, such objects are declared in the following way:
a = {
_p: 'my value', // intended as private
get p() {
return this._p;
},
set p(x) {
this._p = x;
}
};
console.log(a.p); // gives 'my value'
a.p = 'new value';
console.log(a.p); // gives 'new value'
Another way is to use Object.defineProperty() method which lets you to set all needed properties attributes. Like this:
var a = {p: 'my value'};
Object.defineProperty(a, 'p', {
get: function() { return this.p; },
set: function(newValue) { this.p = newValue; },
enumerable: true,
configurable: true
});
because p() method returns nothing hence it returns undefined
if you do
a={get p(){alert(1); return 2;}};
alert(a.p);
it will alert 1 and then 2 since this p() method returned 2
{get p(){alert(1)}}
this is an object that has a getter p
when you use a.p it will use that getter to retrieve some value
so when you do alert(a.p); it first call the getter, so alert 1, then alert the returned value undefined.
[Edit] - You changed your original question so this answer doesn't cover everything.
p is a getter function - It is called whenever you access the p property. In your getter you have alert(1).
The getter function doesn't return anything. Thus, p is undefined. So the alert(a.p) alerts undefined.
Thus, your program does:
Get value of a.p: alert(a.p)
Calls p getter function. Which has alert(1)
p getter function returns nothing
Thus alert(a.p) alerts undefined
function myConstructor (arg) {
this.myName = arg;
this.totalNumber = 0;
this.foo = {
bar: {
someBoolean: false,
someNumber: 5
},
baz: {
someBoolean: false,
someNumber: 10
}
};
}
myConstructor.prototype.getNumber = function () {
console.log(this); //successfully returns the child object
for (var i in this.foo) {
//console log tests
console.log(this); //still returns the child object with all properties, including the myName 'whatever'
console.log(this.foo); //returns the 'foo' object with all nested properties
console.log(i); //returns 'bar' and 'baz', respectively
console.log(this.foo.hasOwnProperty(i)); //returns true
//where it all goes wrong
console.log(typeof(i)); //returns 'string'
console.log(this.foo.i); //returns undefined, even though 'this.foo' definitely has 'bar' and 'baz' properties
//what I'm trying to accomplish
/*
if (this.foo.i.hasOwnProperty('someBoolean') && this.foo.i.someBoolean === true) {
this.totalNumber += this.foo.i.someNumber;
} //returns 'TypeError: Cannot read property 'hasOwnProperty' of undefined
*/
}
return this.totalNumber;
};
var myChild = new myConstructor('whatever');
myChild.getNumber();
What I'm trying to accomplish is using a constructor to create a child. The having nested objects inside that child, with various properties that I will change later in my code. Then using a method of the constructor to access data within the nested objects of that child. Everything works until I get two-deep in nested objects.
I've tried passing every variable, object and property around with various "var this == that"s and "var prop == i"s and etc. Nothing I do seems to work.
foo has no property named i.
You want foo[i], to get the property with that name.
it should be console.log(this.foo[i])
As foo doen not contain "i" property.
Your confusion lies in the way that for-each/for-in loops are normally used in other programming languages such as Java, C#. Here's the difference:
// java
for(int x in list)
x = x+1;
// javascript
var x;
for(x in list)
list[x] = list[x] + 1;
I'm trying to define a non-enumerable toJSON function on a prototype object without much luck. I'm hoping for something similar to ECMAScript 5 toJSON:
Object.defineProperty(obj, prop, { enumerable: false });
However this defines it as a property which cannot be accessed as a method.
[EDIT: Nick is wrong; it can be accessed as a method. His mistake was in code that is not shown in this question - see his comments on answers below, for details.]
I was hoping to be able to define the function in a non-enumerable fashion, as I was planning to define in the prototypes of all primitive types (String, Number, Boolean, Array, and Object), so that I can recursively apply the function through complex objects.
The end goal here is to be able JSONify a Backbone model/collection with nested collections recursively.
I guess in total I have two main questions:
Is it possible to define a non-enumerable function on a prototype? If so how?
Is there a better way to JSONify nested Backbone models?
I don't get it, why can't you access it as a method?
var foo = {};
Object.defineProperty(foo, 'bar', {
enumerable: false,
value: function () {console.log('foo.bar\'d!');}
});
foo.bar(); // foo.bar'd!
If you wanted it on the prototype, it's as easy as
Object.defineProperty(foo.prototype, /* etc */);
or even directly in Object.create
foo.prototype = Object.create(null, {
'bar': {value: function () {/* ... */}}
});
However, unless you're creating instances of foo, it won't show up if you try to foo.bar, and only be visible as foo.prototype.bar.
If foo has it's own prototype (e.g. foo = Object.create({})), you can get it with Object.getPrototypeOf, add the property to that and then foo.bar would work even if it is not an instance.
var proto = Object.getPrototypeOf(foo); // get prototype
Object.defineProperty(proto, /* etc */);
You can see visibility of enumerable vs non-enumerable properties here.
Paul S. is right about needing to set the property definition's value instead of a get, but I wanted to add that you don't need to pass enumerable: false, because false is the default for that option in Object.defineProperty() The answer can be simplified to:
var foo = {};
Object.defineProperty(foo, 'bar', {
value: function(){ console.log('calling bar!'); }
});
foo.bar();
Always you can avoid enumerable functions properties in object when you looping through it. And instead of define property in each object and set enumerable to false , you can create function which will call to any object with the property you want and put a condition to not take the property in the looping list. here is the example :
const obj = {
name: "myName",
title: "developer"
}
function prop() {
this.loop = function(i) {
for (i in this) {
if (typeof(this[i]) == "function") {
continue;
} else {
console.log(this[i]);
}
}
}
}
prop.call(obj);
obj.loop();
output >> myName, developer
I came across this little snippet of code for property reflection in JavaScript:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
if (typeof obj[prop] !== "function") {
result.push(prop);
}
}
return result;
}
I've tested it using the following "CustomObject":
var CustomObject = (function () {
function CustomObject() {
this.message = "Hello World";
this.id = 1234;
}
Object.defineProperty(CustomObject.prototype, "Foo", {
get: function () {
return "foo";
},
enumerable: true,
configurable: true
});
Object.defineProperty(CustomObject.prototype, "Bar", {
get: function () {
return "bar";
},
enumerable: true,
configurable: true
});
return CustomObject;
})();
Here is a little test using jQuery:
$(document).ready(function () {
console.log(GetProperties(new CustomObject()));
});
Here are the results:
["message", "id", "Foo", "Bar"]
I understand that the GetProperties function just returns an array of anything in the input object that is not a function, but I want to filter the results to get only the "real" properties, so my output should be:
["Foo", "Bar"]
Is this possible?
Also, can I do the opposite and just return the fields?
There are two things you could do (and possibly more, it depends on your exact situation):
Name "private" properties differently, e.g. with a trailing underscore and check whether the property name ends with an underscore when you are iterating over the properties (and exclude them).
If by "real properties" you mean the properties defined on the prototype and you want to ignore all properties defined on the object itself, you can use .hasOwnPrototype to check where it is defined. Alternatively, you could use Object.getPrototypeOf and iterate over the properties of the prototype only.
Bad code. I'm leaving (with a comment) it 'cause the subsequent discussion
might help somebody else.
If you always use defineProperty() to get non enumerable properties, then this would work:
function GetProperties(obj) {
var result = [];
for (var prop in obj) {
// propertyIsEnumerable() returns false just because the properties
// are inherited thru the prototype chain. It was just a coincidence
// that it got the desired result. Don't do this.
if (typeof obj[prop] !== "function" && !obj.propertyIsEnumerable(prop)) {
result.push(prop);
}
}
return result;
}
Otherwise, I'd be curious to know a general solution to the problem.
EDIT: I see that the code has enumerable: true and still my code does exactly what was asked. Double you tee ef?