I have all non - enumerable properties in object, I want to clone that object.
My problem non-enumerable properties are not getting cloned.
Take below example
Object.defineProperty(this, 'prop', {
get: function () {
return prop;
},
set: function (value) {
prop= value;
}
});
Object.defineProperty(this, 'newprop', {
get: function () {
return newprop;
},
set: function (value) {
newprop= value;
}
});
For example I have above two properties in my object doing clone using following methods, my properties are not getting cloned I believe it is because they are non - enumerable.
var newObject = $.extend({},oldObject);
var newObject= Object.assign({},oldobject);
How do I copy non-enumerable properties in javascript.
If one or more properties aren't enumerable, how do you want to auto-magically enumerate them?
Since you know their names, you should do something like this:
var sourceObj = this;
var targetObj = {};
["prop", "otherProperty"].forEach(function(property) {
targetObj[property] = sourceObj[property];
});
Or you can build the whole property name array whenever you define a non-enumerable property:
var propertyNames = [];
Object.defineProperty(this, 'newprop', {
get: function () {
return newprop;
},
set: function (value) {
newprop= value;
}
});
propertyNames.push("newprop"); // <---
Object.defineProperty(this, 'newprop2', {
get: function () {
return newprop;
},
set: function (value) {
newprop= value;
}
});
propertyNames.push("newprop2"); // <---
propertyNames.forEach(function(property) {
targetObj[property] = sourceObj[property];
});
Alternate approach: Object.getOwnPropertyNames
The Object.getOwnPropertyNames() method returns an array of all
properties (enumerable or not) found directly upon a given object.
Maybe this is the best approach. Object.getOwnPropertyNames gets the name of own object's properties either if they're enumerable or not. That is, you can avoid building the whole propertyNames array, and this approach should be fine with you because you said that all properties aren't enumerable:
var sourceObj = this;
var targetObj = {};
Object.getOwnPropertyNames(sourceObj).forEach(function(property) {
targetObj[property] = sourceObj[property];
});
You can use Object.defineProperties and Object.getOwnPropertyDescriptors() function
The Object.defineProperties() method defines new or modifies existing properties directly on an object, returning the object.
The Object.getOwnPropertyDescriptors() method returns all own property descriptors of a given object.
So, you can add the properties of the original object into an empty object, as follow
var source_obj = this
var cloned_obj = Object.defineProperties({}, Object.getOwnPropertyDescriptors(source_obj));
I have a similar question in How to implement Ruby's extend module in JavaScript.
And because I don't wanna use iterate attach each method to new object, so the final best way I can do is like that, welcome give me any idea and suggestion, thanks.
class Test {
constructor(name) {
this.name = name;
}
test1(){
return this.name + "test1"
}
}
const Other = {
test2: function(){
return this.name + "test2"
},
test3: function(){
return this.name + "test3"
},
test4: function(){
return this.name + "test4"
}
}
var person = new Test("HKE")
Object.assign(person,Other) //this like object.extend(Module) in ruby
console.log(person.test1()) // HKEtest1
console.log(person.test2()) // HKEtest2
console.log(person.test3()) // HKEtest3
console.log(person.test4()) // HKEtest4
var house = new Test("Tsao")
console.log(house.test1())
console.log(house.test2()) // TypeError: house.test2 is not a function
console.log(house.test3()) // TypeError: house.test3 is not a function
console.log(house.test4()) // TypeError: house.test4 is not a function
Related
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.
I am following a tutorial to create getter and setter in Javascript, I have the code like this:
// Create a new User object that accept an object of properties
function User(properties) {
// Iterate through the properties of the object, and make
// sure it's properly scoped
for (var i in properties) { (function(){
// Create a new getter for the property
this['get' + i] = function() {
return properties[i];
};
// Create a new setter for the property
this['set' + i] = function(val) {
properties[i] = val;
};
})(); }
}
// Create a new User object instance and pass in an object of
// properties to seed it with
var user = new User({
name: 'Bob',
age: 28
});
// Just note that the name property does not exist, as it's private
// within the property object
console.log(user.name == null);
// However, we are able to access its value using the new getname()
// method, that was dynamically generated
console.log(user.getname());
However, console shows error saying user does not have method getname. The code is trying to dynamically generate getter and setter method, it looks ok to me. Any thoughts?
The other answers are correct in that you need to pass i into your anonymous function, but you could also do this with ES5 Getters and Setters:
// Create a new User object that accept an object of properties
function User(properties) {
var self = this; // make sure we can access this inside our anon function
for (var i in properties) {
(function(i) {
Object.defineProperty(self, i, {
// Create a new getter for the property
get: function () {
return properties[i];
},
// Create a new setter for the property
set: function (val) {
properties[i] = val;
}
})
})(i);
}
}
The benefit of using ES5 getters and setters is that now you can do this:
var user = new User({name: 'Bob'});
user.name; // Bob
user.name = 'Dan';
user.name; // Dan
Since they're functions, they modify the passed in properties, not just the object itself. You don't have to use getN or setN anymore, you can just use .N, which makes using it look more like accessing properties on an object.
This approach, however, isn't universally portable (requires IE 9+).
Here's what I'd probably do in practice though:
function User(properties) {
Object.keys(properties).forEach(function (prop) {
Object.defineProperty(this, prop, {
// Create a new getter for the property
get: function () {
return properties[prop];
},
// Create a new setter for the property
set: function (val) {
properties[prop] = val;
}
})
}, this);
}
The above gets rid of your for loop. You're already using an anonymous function, so might as well get the most of it.
Probably a closure issue:
function User(properties) {
// Iterate through the properties of the object, and make
// sure it's properly scoped
for (var i in properties) {
(function(i){
// Create a new getter for the property
this['get' + i] = function() {
return properties[i];
};
// Create a new setter for the property
this['set' + i] = function(val) {
properties[i] = val;
};
}.call(this, i));
}
}
Also, as #Paul pointed out, this was actually referring to the function which was contained in the for loop. Not the User function. I fixed that by using a call and assigning the User this to the function (no need for extra variable).
Your in-loop function is losing the this, do a var t = this; outside loop and refer to t inside. Also, pass i into your function.
function User(properties) {
var t = this, i;
for (i in properties) (function (i) {
t['get' + i] = function () { return properties[i]; };
t['set' + i] = function (val) { properties[i] = val; };
}(i));
}
I have a JavaScript object defined like so:
var Object = (function () {
function Object() {
this.id = RandomNumber();
}
// Custom Object.prototype / Object impementations here...
return Object;
})();
The problem is that once this has been constructed, it loses original functionality like Object.defineProperty etc.
The idea is that I want to extend the basic functionality of Object, not re-write or overwrite the existing prototype.
How can this be achieved?
EDIT: Just to be clear, I know I can do this without affecting the original functionality:
Object.prototype.foo = function() { }
but I need to specifically add functionality to Object's constructor, i.e.
function Object() { this.id = 0; }
The new functionality must not overwrite the original Functionality.
Use the .prototype to add a property:
Object.prototype.specialMethod = function () {
// Your method's code
};
And you'd use it like:
var a = {};
a.specialMethod();
Although I would discourage adding a property to the Object's prototype, because it is enumerable and will mess up looping, and will be inherited by all objects, and objects that inherit from Object, which is basically everything.
You could actually use the Object.defineProperty method you mention:
Object.defineProperty(Object.prototype, "specialMethod", {
enumerable: false, // The important one, to avoid looping problems
configurable: false,
writable: false,
value: function () {
// Your method's code
}
});
Do as Ian wrote. If you also want to check it the method already exists use
if (Object.prototype.specialMethod == null) Object.prototype.specialMethod = function() { ... };
In order to extend this object you should create another object that has its prototype assigned a new instance of Object.
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/
If you want to stick with the self executing functions here is the example rewrote:
var Object = (function () {
function Object() {
this.id = 5;
}
Object.prototype.speak = function(prop){
alert(this[prop]);
}
return Object;
})();
var ExtendsObject = (function(){
function ExtendsObject(prop){
this.someProperty = prop;
}
ExtendsObject.prototype = new Object();
return ExtendsObject;
})();
var xObj = new ExtendsObject("derived");
xObj.speak("id");
xObj.speak("someProperty");
Working Example: http://jsfiddle.net/RbCcA/1/
I do question the use of self executing functions in this situation. They are usually used to encapsulate and shield internals, however in the code example they are being exposed by returning the object from the SEF. Returning the object and storing it in a global variable just re-exposes the object, allowing its prototype and properties to be manipulated. Maybe there are private variables you have not mentioned, but as stated I find the SEFs unnecessary.
Consider this code...
var org = {};
org.Organization = function() {
var app = null;
function setupApplication() {};
return {
init : function() {
console.log("init");
}
}
};
org.Organization.prototype = {
status : function() {
console.log("status");
}
};
var myOrg = new org.Organization();
myOrg.init(); // outputs "init"
myOrg.status(); // TypeError: Object #<Object> has no method 'status'
... the status() method does not exist and I can't call it :( However, if I were to remove the return { ... } like so...
var org = {};
org.Organization = function() {
var app = null;
function setupApplication() {};
};
org.Organization.prototype = {
status : function() {
console.log("status");
}
};
var myOrg = new org.Organization();
myOrg.init(); // TypeError: Object #<Object> has no method 'init
myOrg.status(); // outputs "status"
... then the status() method does exist and I can call it with no problems. Why is this happening? Why can a method on the prototype chain be called only when original object has no return { ... }? Does the return { ... } overwrite or take precedence over the methods on the prototype chain?
When you use return obj in a function constructor, it will return that actual object, not the object that has been constructed internally. If you want it to work correctly, simply define init within the constructor like so:
this.init = function() { };
To give a few more details: when you call new Func, what happens internally is that a new object (with the prototype set to the function's prototype) is created and the constructor function is called with the object set as this. At the end of the constructor, the same object is returned, unless you return another object manually, in which case that object will be returned, which will obviously not have the same prototoype.
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/