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.
Related
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
I ran into a problem using instanceof in JavaScript:
var MyObject = function() {
var prop = {};
return prop;
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // return false;
Instanceof returns Object instead of the expected MyObject. I can't remove "return prop"; How can I get the type MyObject for testObject ?
Thanks for helping
EDIT: Even if my question looks like this one: What's wrong with a JavaScript class whose constructor returns a function or an object, mine needed a bit more explanation about what a new does.
You could probably break it into steps based on what the new operator does
var MyObject = function () {
var prop = {};
return prop;
}
var testObject = Object.create(MyObject.prototype);
var result = MyObject.call(testObject);
// result is the actual output of new MyObject();
result = result && typeof result === 'object' ? result : testObject;
console.log(testObject instanceof MyObject); // returns true
console.log(result instanceof MyObject); // returns false because it's actually prop (i.e. {})
What we have done is replace the new with the actual steps that happen when you do a new. Below are the steps
Create an object whose prototype is the same as the function's (constructor's) prototype. This is what var testObject = Object.create(MyObject.prototype);
Call the (constructor) function with this set to this newly created object. This what var result = MyObject.call(testObject); does (the first parameter being the value of this for the MyObject invocation)
If the function returns a non null object, the new ... expression evaluates to that value. Otherwise it evaluates to the object created in Step 1.
For the question, the last step's non null return value (prop = {}) was getting in the way of our actually testing the type of the object returned in Step 1. By splitting it into component steps we can get the created object (and use that in the instanceOf test)
If you can at least modify prop, then you could add a flag to it:
var MyObject = function() {
var prop = { _isMyObject: true }
return prop;
};
Then you could have a function that checks for that flag.
function isMyObject(obj) {
return obj._isMyObject ? true : false;
}
You will see why if you try this:
var MyObject = function() {
var prop = { testProp: 1 };
return prop;
}
var testObject = new MyObject();
console.log(testObject.testProp); // returns 1;
If in a class constructor you return an object, the newly instantiated object of that will become that returned object. If you return a primitive value, it will instead become an instance of the object as your originally expected.
So, if you apply Object.prototype.toString() method on your prop object and instead return the result of that (a string primitive), you get your desired MyObject back:
var MyObject = function() {
var prop = {};
return prop.toString();
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // returns true;
It's because when you do
var MyObject = function() {
var prop = {};
return prop;
}
you are assigning a function to the variable MyObject. Not creating a custom object MyObject. In order to create a custom object, you need to use the syntax
function MyObject() {
var prop = {};
return prop;
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // return true;
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
i am new to oop in javascript.
var obj1 = {
name : 'honda',
getName : function(){
console.log(this.name);
}
}
var obj2 = {name:'maruti'};
I want to access getName of obj1 with scope of obj2, like obj2.getName().
Is this what you want:
obj1.getName.call(obj2);
As #roland said, you can also use .apply(obj2, [arr of args]) if you want to provide an array of arguments to the method.
EDIT:
If you want to import all obj1 methods into obj2, you can do that with pure JavaScript:
for (var m in obj1) {
// if you want to copy obj1's attributes, remove this line
if (obj1[m] instanceof Function) {
obj[2][m] = obj1[m];
}
}
Or you can do it with jQuery:
$.extend(obj2, obj1);
If are looking to use obj1 as a template for creating new objects, you can use Object.create to do this.
var obj1 = {
name : 'honda',
getName : function(){
console.log(this.name);
}
}
var obj2 = Object.create(obj1);
obj2.name = 'bob';
obj2.getName(); // outputs 'bob'
I have an object:
obj = {
obj1: {
name: "Test";
}
}
and function:
var anon = function(a) {
alert(obj.a.name);
}
I want to give as an argument "obj1". Im newbie to programming so I think I should get alert with "Test" but it doesn't work. How to give reference with argument?
You can do this way: You can always access properties of the object as obj[key], thats what we are doing here.
var anon = function(a) {
alert(obj[a].name);
}
and remove ; from the inline object property definision syntax.
obj = {
obj1: {
name: "Test"; //<-- Here
}
}
http://jsfiddle.net/RuCnU/
This Link can provide you some basic insight on object and keys.
var anon = function(a) {
alert(obj[a].name);
}
When you are looking up the property of an object using a string use square brackets, the obj.a will only work if the object has a property named a, for example obj = {a: "Test"}.
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/