Why true? How method foo written in the object?
Object.prototype.foo = function(obj) {
for(var i in obj) this[i] = obj[i];
};
var obj = {a: 1};
var testObj = {};
testObj.foo(obj)
alert( testObj.hasOwnProperty("foo") );
A for ... in loop iterates through all of the visible properties of the target objects, including those on its prototype chain.
If you only want to transfer the "own" properties of the source object, you can add a test:
Object.prototype.foo = function(obj) {
for(var i in obj)
if (obj.hasOwnProperty(i))
this[i] = obj[i];
};
When you use testObj.foo(obj), the foo method is called with the this value set to testObj.
Therefore, this code...
for(var i in obj) this[i] = obj[i];
...adds the enumerable (own or inherited) properties of obj as own properties of this (testObj in this case).
And foo is an enumerable (inherited) property of obj, so it is added to testObj.
Object.prototype.foo = function(obj) {
for(var i in obj) this[i] = obj[i];
};
var obj = {a: 1};
var testObj = {};
alert( testObj.hasOwnProperty("foo") ); // false
testObj.foo(obj)
alert( testObj.hasOwnProperty("foo") ); // true
As you can see the foo method is attached to the object after foo is called.
Why? Because for..in will iterate through all keys which are enumerable, regardless if they live on the object or on one of its prototypes.
Object.prototype.foo = function(obj) {
for ( var i in obj ) {
console.log(i, '=', obj.hasOwnProperty(i)); // foo=false
}
};
The 'foo' method is enumerable, you can check using
Object.prototype.propertyIsEnumerable("foo") // true
How do you make a property non-enumerable?
Object.defineProperty(Object.prototype, 'foo', {
'configurable': true, // can be removed using 'delete' operator
'enumerable': false, // will not show up in a for..in iteration
'writable': true, // can be overridden
'value': function () {
for ( var key in this ) {
console.log(key, '=', this.hasOwnProperty(key));
}
}
});
Just in case you were wondering:
Object.prototype.propertyIsEnumerable("hasOwnProperty") // false
Object.prototype.propertyIsEnumerable("propertyIsEnumerable") // false
Related
Here's the object defination:
var Vars = new function(){
var that = this;
this.assign = function(name) {
var realValue = undefined;
Object.defineProperty(that, name, {
configurable: true,
get: function() {
//console.log("Get"); do something...
return realValue;
},
set: function(v) {
//console.log("Set"); do something...
realValue = v;
}
});
}
this.destroy = function(name) {
return delete that[name];
}
};
But i found i cannot iterate over this object by the way i want.
>> Vars.assign("key")
<- undefined
>> Vars.key = 1
<- 1
>> Vars.key
<- 1
>> for(var i in Vars){console.log(i);}
assign
destroy
<- undefined
How could i reach "key" when i iterate over the object?
You have to state explicitly at the property descriptor that your property is enumerable. The default value is false. This is the reason why you don't get it when you use the for..in. According to MDN
The for...in statement iterates over the enumerable properties of an
object, in arbitrary order. For each distinct property, statements can
be executed.
Regarding the enumerable property, as it is stated here:
enumerable
true if and only if this property shows up during
enumeration of the properties on the corresponding object. Defaults to
false.
var Vars = new function(){
var that = this;
this.assign = function(name) {
var realValue = undefined;
Object.defineProperty(that, name, {
configurable: true,
// This is the missing line
enumerable: true,
get: function() {
//console.log("Get"); do something...
return realValue;
},
set: function(v) {
//console.log("Set"); do something...
realValue = v;
}
});
}
this.destroy = function(name) {
return delete that.Local[name];
}
};
Vars.assign("key");
for(var i in Vars){console.log(i);}
i have created an object as follows
var lassie = {
name: 'Lassie',
breed: 'Collie',
speak: function () {
return 'Woof! Woof!'; }
};
I create another object by using Object.create method of javascript as
var obj = Object.create(lassie);
now when i console obj it gives me a blank object.
But when i console obj.speak() it gives me 'Woof! Woof!' .
can someone please explain why?
Pass lassie as first parameter to Object.create() to set prototype of obj to lassie; iterate lassie return properties as second parameter
var lassie = {
name: 'Lassie',
breed: 'Collie',
speak: function() {
return 'Woof! Woof!';
}
};
var obj = Object.create(lassie, (function() {
var _obj = {};
for (var prop in lassie) {
_obj[prop] = {
value: lassie[prop],
writable: true,
enumerable: true,
configurable: true
}
}
return _obj
}()));
alert(obj.speak())
var obj = Object.create(lassie);
By doing this you have created a new object which inherits the properties from lassie.
if you do
obj.name; //this prints "Lassie" too.
Basically Object.create will create an object that would have no own properties. That means the passed object's own properties would be assigned as the prototype properties of the newly created object and that would be returned.
A sample structure of the object returned from Object.create(),
var obj = {a:10};
var obj1 = Object.create(obj);
console.log(obj1); // {... __proto__ : {a : 10 ...}}
If you want to copy the own propties(enumerable) of the passed object to another one object, then you have to can Object.assign(obj) as an alternate to passing second parameter as property descriptor properties for Object.create
var lassie = {
name: 'Lassie',
breed: 'Collie',
speak: function () {
return 'Woof! Woof!'; }
};
var obj = Object.create(lassie);
Now your concern is now when You console obj it gives me a blank object. But when you console obj.speak() it gives you 'Woof! Woof!' .
Actually here obj has now all the properties of lassie ,but these are not the obj own properties.
Here you will see all the properties of obj:
for(var a in obj){
console.log(a);
}
Here you will see obj's own property:
for(var b in obj){
if (obj.hasOwnProperty(b)) {
console.log(b);
}
}
This is actually because when we use var target = Object.create(obj);
then all the properties are added to target as a prototype properties.
Edit: I realized I passed MyConstructorFunc.prototype to `_.extend().
I ran into an interesting implementation detail when I wanted to extend a function with Underscore.
I built a function constructor,
var MyConstructorFunc = function() {
...
}
then I returned the result of
return _.extend(MyConstructorFunc.prototype, {
\\ ...some properties...
}
What I got back was a typeof MyConstructorFunc == "object"! If _.extend is merging properties into a function why does it return an object?
Looking at the _.extend function I don't see where that happens...
_.extend = function(obj) {
if (!_.isObject(obj)) return obj;
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
if (hasOwnProperty.call(source, prop)) {
obj[prop] = source[prop];
}
}
}
return obj;
};
If I do MyConstructorFunc["someProp"] = someObject["someProp"] and return MyConstructorFunc, I returned a JavaScript object?
I'm missing something...
You are probably passing in a Function object to _.extend. Your sample code does not show it, but if you are making a new instance of your MyConstructorFunc using the "new" keyword, then the result will be an object.
var MyConstructorFunc = function() {
}
var foo = _.extend(MyConstructorFunc, {a:1});
console.log(typeof foo); // function
var funcObj = new MyConstructorFunc();
console.log(typeof funcObj); //object
Extending the MyConstructorFunc itself will return a function type. It's once you use the contructor to create a new function that you are given an object.
In Javascript, if an object has lots of properties that are functions:
var obj = { foo: function() { ... },
bar: function() { ... },
...
}
then how can you get an array of names of those functions? That is, an array
["foo", "bar", ... ]
thanks.
var names = [];
for( var k in obj ) {
if(obj.hasOwnProperty(k) && typeof obj[k] == 'function') {
names.push(k);
}
}
var functions = [];
for (var prop in obj) {
if ((typeof obj[prop]) == 'function') {
// it's a function
functions.push(prop);
}
}
Edit: I've slightly misread the question, you want to extract the names of only the properties that are function objects:
function methods(obj) {
var result = [];
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] == 'function') {
result.push(prop);
}
}
return result;
}
var obj = {
foo: function() { },
bar: function() { },
};
methods(obj); // ["foo", "bar"]
I'm using the hasOwnProperty method, to ensure that the enumerated properties in fact exist physically in the object.
Note that this approach and all other answers have a small problem IE.
The JScript's DontEnum Bug, custom properties that shadow non-enumerable properties (DontEnum) higher in the prototype chain, are not enumerated using the for-in statement, for example :
var foo = {
constructor : function() { return 0; },
toString : function() { return "1"; },
valueOf : function() { return 2; }
toLocaleString : function() { return "3"; }
};
for (var propName in foo ) { alert(propName); }
The object foo clearly has defined four own properties, but those properties exist in Object.prototype marked as DontEnum, if you try to enumerate the properties of that object with the for-in statement in IE, it won't find any.
This bug is present on all IE versions, and has been recently fixed in IE9 Platform Preview.
To complete other answers: you can also use instanceof:
var obj = { foo: function() { ... },
bar: function() { ... },
...
},
fnArr = [];
for (var label in obj){
if (obj[label] instanceof Function){
fnArr.push(label)
}
}
With ES5:
var obj = {
foo: function() {},
bar: function() {},
baz: true
};
function getMethods(object) {
return Object.keys(object).filter(function(key) {
return typeof object[key] == 'function';
});
}
getMethods(obj); // [foo, bar]
Object.keys(<object>) returns the names of all enumerable properties of an object as an array, of which the non-functions are filtered out.
Example - works on Chrome release and nightly builds of Webkit and Tracemonkey (Firefox).
I'm trying to extend Object functionality this way:
Object.prototype.get_type = function() {
if(this.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this;
}
}
It's great, but there is a problem:
var foo = { 'bar' : 'eggs' };
for(var key in foo) {
alert(key);
}
There'll be 3 passages of cycle.
Is there any way to avoid this?
I, for one, am not completely against extending native types and ECMA-262 5th ed. solves the problems mentioned in other answers and linked articles for us in a nice manner. See these slides for a good overview.
You can extend any object and define property descriptors that control the behavior of those properties. The property can be made non enumerable meaning when you access the objects properties in a for..in loop, that property will not be included.
Here's how you can define a getType method on Object.prototype itself, and make it non enumerable:
Object.defineProperty(Object.prototype, "getType", {
enumerable: false,
writable: false,
configurable: false,
value: function() {
return typeof this;
}
});
// only logs "foo"
for(var name in { "foo": "bar" }) {
console.log(name);
}
The getType function above is mostly useless as it simply returns the typeof object which in most cases will simply be object, but it's only there for demonstration.
[].getType();
{}.getType();
(6).getType();
true.getType();
You shouldn't extend the object prototype, for that exact reason:
http://erik.eae.net/archives/2005/06/06/22.13.54/
Use a static method instead.
If you have no choice, you can use the "hasOwnProperty" method:
Object.prototype.foo = function(){ alert('x'); }
var x = { y: 'bar' };
for(var prop in x){
if(x.hasOwnProperty(prop)){
console.log(prop);
}
}
You can use the hasOwnProperty() method to check if the property belongs to the foo object:
var foo = { 'bar' : 'eggs' };
for (var key in foo) {
if (foo.hasOwnProperty(key)) {
alert(key);
}
}
Is there any way to avoid this?
Yes, don't extend native types.
Use a wrapper instead:
var wrapper = (function(){
var wrapper = function(obj) {
return new Wrapper(obj);
};
function Wrapper(o) {
this.obj = obj;
}
Wrapper.prototype = wrapper.prototype;
return wrapper;
}());
// Define your get_type method:
wrapper.prototype.get_type = function(){
if(this.obj.constructor) {
var r = /\W*function\s+([\w\$]+)\(/;
var match = r.exec(this.obj.constructor.toString());
return match ? match[1].toLowerCase() : undefined;
}
else {
return typeof this.obj;
}
};
Usage:
var obj = { 'bar' : 'eggs' };
alert(wrapper(obj).get_type());
for(var i in obj) { ... works properly }
When you loop over enumerable properties of an object, you can can determin if the current property was "inherited" or not with Object.hasOwnProperty()
for ( var key in foo )
{
if ( foo.hasOwnProperty( key ) )
{
alert(key);
}
}
But let the dangers of monkey patching be known to ye, especially on Object, as others have posted about
Create your own object instead of extending the default Object.
Also see:
http://erik.eae.net/archives/2005/06/06/22.13.54/
http://dean.edwards.name/weblog/2006/07/erlaubt/