How can I test if two javascript objects are similar? - javascript

In Javascript (no jquery or other frameworks please) I want to test if 2 (or more) objects are the same type of object.
Here are some sample objects:
function Person (firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
function Animal (name, type, age) {
this.name = name;
this.type = type;
this.age = age;
}
var family = {};
family.father = new Person ('John', 'Doyle', 33);
family.mother = new Person ('Susan', 'Doyle', 32);
family.pet = new Animal ('Jodie', 'Cat', 2);
Given the above objects, I want a generic way to test if family.father, family.mother, and family.pet are from the same "type" of object. Can I test for the difference between Person and Animal in a generic way. Something like:
if ( sourceObject(family.father) === sourceOjbect(family.mother) ) {
alert('father and mother are the same type');
} else {
alert('father and mother are not from the same object... we could have problems.');
}
if (sourceObject(family.pet) !== sourceObject(family.father)) {
alert('the pet is a different type than the father');
} else {
alert('Perhaps it should be a child instead of a pet?');
}
or perhaps something like this:
if (isSameObject(family.pet, family.father)) {
alert('Perhaps it should be a child instead of a pet?');
} else {
alert('Father and pet are different.');
}
There is no "sourceObject" function, but I'm trying to find out if there IS something that does this or someone has found a quick way to do that comparison.
Note I am not looking to compare the data in the objects, I am looking to compare the type of Objects involved in the comparison. I need to do this without knowing the exact make up of the components involved. For example, in the above code I could test for a "type" property, but that requires foreknowledge of the objects. I am trying to write a generic function that will not necessarily know anything about the objects passed to it other than the objects them selves.

You can compare their constructors, as such
family.father.constructor == family.mother.constructor
MDC about constructors
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
JSFiddle
http://jsfiddle.net/8LvN5/

Use constructors: http://jsfiddle.net/uME8m/
alert(family.father.constructor === family.mother.constructor); //true
alert(family.father.constructor === family.pet.constructor); //false

You can compare using .constructor or .constructor.name.
family.father.constructor == family.mother.constructor
family.father.constructor == family.pet.constructor
More on objects you can see here.
If you want to construct a function, you can do:
function sourceObject(obj) {
return obj.constructor; // you can return obj.constructor.name as well
}

You could compare the prototype, based on prototypical inheritance.
EDIT: might be better to compare constructors, for browser compatibility...
family.father.__proto__ == family.mother.__proto__ //EDIT: doesn't work in IE
//so
family.father.constructor == family.mother.constructor
so, in general:
function isSameObject(obj1, obj2){ //is same prototype - actaully;
return obj1.constructor == obj2.constructor
}
http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/

You can use Object.getPrototypeOf() (MDN Resource) to get the internal [[prototype]] property and then simply compare those two properties:
function isSameObject(obj1, obj2) {
return Object.getPrototypeOf(obj1) === Object.getPrototypeOf(obj2);
}
This should work in every modern browser, starting with IE9.
The advantage compared to the constructor property, is that the constructor property can be easily accidentally overridden, for instance when implementing inheritance:
function A() {
}
function B() {
}
B.prototype = Object.create(A.prototype);
var b = new B();
console.log(b.constructor); //A
FIDDLE

Related

What is a JavaScript instance?

What is an instance in JavaScript? Can anyone provide an example please?
Also, please explain your code.
An instance is simply an object that was created by a class (ES6) or constructor function. Here's an example:
function Person(name) {
this.name = name;
}
var john = new Person("John Doe");
console.log(john);
//john is an instance of Person - we can see this by using the instanceof operator
console.log(john instanceof Person);
JavaScript makes instances when defining variables, but these are only accessible by using typeof unless you explicitly use the new constructor to make your variable:
var str = "Foo Bar";
var num = 123;
var bool = true;
var obj = { abc: "def" }
var arr = [true, 1, "s"];
console.log(typeof str);
console.log(typeof num);
console.log(typeof bool);
console.log(typeof obj);
console.log(typeof arr);
console.log(typeof undefined);
console.log(typeof null);
There are a couple of tricks with typeof though - typeof [] == "object" because an array is an object with a few different methods. The other most common issue is typeof null == "object", because of a discrepancy when JavaScript was created between null and undefined.
If you want to find the constructor of any value, use constructor.name:
var str = "Foo Bar";
var num = 123;
var bool = true;
var obj = { abc: "def" }
var arr = [true, 1, "s"];
console.log(str.constructor.name);
console.log(num.constructor.name);
console.log(bool.constructor.name);
console.log(obj.constructor.name);
console.log(arr.constructor.name);
This trick also works with your own constructors and classes:
function Person(name) {
this.name = name;
}
var john = new Person("John Doe");
console.log(john.constructor.name);
When you create an object !
Example:
//instancing a image
var myImage = new Image(100, 100);
//Append in to body
document.querySelector("body").appendChild(myImage);
Simply put, in object-oriented programming, there are classes and objects. When you instantiate, or create an instance of a class, you get an object.
For example, take the following Car class:
function Car(myVin) {
this.vin = myVin;
}
let myHonda = new Car(“24A6733HJ42983C55”);
let myFord = new Car(“JJ67100473KL93228”);
let momsMinivan = new Car(“JF293HJL679904611”);
You just instantiated the Car class three times. Each is an instance.
ES2015 (aka ES6) introduces the class keyword, and constructors:
class Car {
constructor(myVin) {
this.vin = myVin;
}
}
This gets much more involved.
IMO, If you really want to learn OO programming, it’s really best to learn the C++ way first. There you’ll see classical inheritance at work, with concepts of constructors, private, protected, and public data members, design patterns, and other key concepts. This will build a solid foundation before you dive into the kluge that is Ecmascript classical inheritance.
Under the hood, Javascript has prototypical inheritance; Ecmascript plasters classical inheritance on top. It’s is a little weird and hacky, and have to do strange things with closures to achieve privacy.
See link below for a good lesson on OOP in C++.
https://m.youtube.com/watch?v=vz1O9nRyZaY
Let there be an object with properties id, name, and age. Now you want to create 100
objects that represent 100 people. Each person will have an id, name, and age.
You can create objects like:
var person1 = {
id: 1,
name: “p1”,
age: 20
};
var person2 = {
id: 2,
name: “p2”,
age: 21
};
….. And so on.
But instead of creating 100 objects by individually defining id, name, and age for all of
them, you create a standard template with properties id, name, and age. Then use
this template to create objects and set the required values.
This standard template can be seen as an object. Each time you create a new
object by using the new keyword, you create a new instance of an already-defined object with already-specified
properties.
For that, you can do this:
function people(id, name, age){
this.id = id;
this.name = name;
this.age = age;
}
let people1 = new people(1,'rani',20);
let people2 = new people(2,'rahul',21);
let people3 = new people(3,'adi',20);
.
.
.
and so on.
Here people1, people2, and people3 are the instances.

JavaScript - check for existence of a prototype instance within an object

I want to check an object to see if any instances of the carDoor prototype exist
function carDoor(side) {
this.side = side;
}
var Car = {
"door1": new carDoor("left"),
"door2": new carDoor("right")
}
Does the Car object have a door? - How can I check in a way that will work for any prototype?
Assume that you don't know or control the name of the property.
You can use the instanceof operator:
for (key in Car) {
if (Car.hasOwnProperty(key)) {
if (Car[key] instanceof carDoor) {
// ...
}
}
}
In your example, you could do:
Car.door1.constructor === carDoor;
That will return true.
You answered your question.. or at least a half of it, verify the constructor of the Car object properties and it'll return true.
if (Car.door2.constructor === carDoor)
// ...

why prototype is undefined

I known this has been asked hundreds of times, however, I can't seem to grasp the concept of prototype
Here's my sample script
var config = {
writable: true,
enumerable: true,
configurable: true
};
var defineProperty = function(obj, name, value) {
config.value = value;
Object.defineProperty(obj, name, config);
}
var man= Object.create(null);
defineProperty(man, 'sex', "male");
var person = Object.create(man);
person.greet = function (person) {
return this.name + ': Why, hello there, ' + person + '.'
}
var p=Object.getPrototypeOf(person);
alert(p.sex);//shows male
person.prototype.age=13;//why there is a error said the prototype is undefined? I thought it supposed be man object...
var child=function(){}
child.prototype.color="red";//why this line doesn't show error? both child and person are an object .
alert(child.prototype.color);//shows red
var ch=Object.getPrototypeOf(child);
alert(ch.color);//why it is undefined? it is supposed red.
Hope you can give me some helps... thanks.
Updated:
Thanks your guys kindly help, Based on Elclanrs's answer, Below is what I learned.
Function is the one of the build-in objects in javascript. the 3 format creation function object are equal.
var function_name = new Function(arg1, arg2, ..., argN, function_body)
function function_name(arg1, arg2, ..., argN)
{
...
}
var function_name=function(arg1, arg2, ..., argN)
{
...
}
So, that is why create a prototype chain we have to create a function and then call it with the new keyword .
Function.prototype is the reference to All the Function object prototype.
Cheers
The prototype property only exists on functions, and person is not a function. It's an object.
Here's what's happening:
var man = Object.create(null); // man (object) -> null
man.sex = "male";
var person = Object.create(man); // person (object) -> man (object) -> null
person.greet = function () { ... };
var p = Object.getPrototypeOf(person); // man (object) -> null
alert(p.sex); // p is the same object as man
person.prototype.age = 13; // person doesn't have a prototype
var child = function () {}; // child (function) -> Function.prototype
// -> Object.prototype -> null
child.prototype.color = "red"; // child has a prototype
var ch = Object.getPrototypeOf(child); // Function.prototype
alert(ch.color); // ch is not the same as color.prototype
// ch is Function.prototype
For more information I suggest you read this answer: https://stackoverflow.com/a/8096017/783743
Edit: To explain what's happening in as few words as possible:
Everything in JavaScript is an object except primitive values (booleans, numbers and strings), and null and undefined.
All objects have a property called [[proto]] which is not accessible to the programmer. However most engines make this property accessible as __proto__.
When you create an object like var o = { a: false, b: "something", ... } then o.__proto__ is Object.prototype.
When you create an object like var o = Object.create(something) then o.__proto__ is something.
When you create an object like var o = new f(a, b, ...) then o.__proto__ is f.prototype.
When JavaScript can't find a property on o it searches for the property on o.__proto__ and then o.__proto__.__proto__ etc until it either finds the property or the proto chain ends in null (in which case the property is undefined).
Finally, Object.getPrototypeOf(o) returns o.__proto__ and not o.prototype - __proto__ exists on all objects including functions but prototype only exists on functions.
I think you might be mixing concepts. Try grasping the concept of prototypes with classic prototype inheritance first, then you can get into all the new Object stuff.
In JavaScript, every object (numbers, strings, objects, functions, arrays, regex, dates...) has a prototype which you can think of as a collection of methods (functions) that are common to all current and future instances of that object.
To create a prototype chain you have to create a function and then call it with the new keyword to specify that it is a constructor. You can think of constructors as the main function that takes the parameters necessary to build new instances of your object.
Having this in mind, you can extend native objects or create your own new prototype chains. This is similar to the concept of classes but much more powerful in practice.
Similar to your example, you could write a prototype chain like this:
// Very basic helper to extend prototypes of objects
// I'm attaching this method to the Function prototype
// so it'll be available for every function
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
}
// Person constructor
function Person(name, age, sex) {
// Common to all Persons
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype = {
// common to all Persons
say: function(words) {
return this.name +'says: '+ words;
}
};
// Student constructor
function Student(name, age, sex, school) {
// Set the variables on the parent object Person
// using Student as a context.
// This is similar to what other laguanges call 'super'
Person.call(this, name, age, sex);
this.school = school; // unique to Student
}
Student.inherits(Person); // inherit the prototype of Person
var mike = new Student('Mike', 25, 'male', 'Downtown'); // create new student
console.log(mike.say('hello world')); //=> "Mike says: hello world"
In newer version of JavaScript (read EcmaScript) they added new ways to deal with objects and extend them. But the concept it's a bit different from classical prototype inheritance, it seems more complicated, and some more knowledge of how JS works underneath would help to really understand how it works, plus it doesn't work in older browsers. That's why I suggest you start with the classical pattern for which you'll find accurate and abundant information on the internet.

In Javascript, the difference between 'Object.create' and 'new'

I think the difference has clicked in my head, but I'd just like to be sure.
On the Douglas Crockford page Prototypal Inheritance in JavaScript, he says
In a prototypal system, objects inherit from objects. JavaScript,
however, lacks an operator that performs that operation. Instead it
has a new operator, such that new f() produces a new object that
inherits from f.prototype.
I didn't really understand what he was trying to say in that sentence so I performed some tests. It seems to me that the key difference is that if I create an object based on another object in a pure prototypal system, then all the parent parent members should be on the prototype of the new object, not on the new object itself.
Here's the test:
var Person = function(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.toString = function(){return this.name + ', ' + this.age};
// The old way...
var jim = new Person("Jim",13);
for (n in jim) {
if (jim.hasOwnProperty(n)) {
console.log(n);
}
}
// This will output 'name' and 'age'.
// The pure way...
var tim = Object.create(new Person("Tim",14));
for (n in tim) {
if (tim.hasOwnProperty(n)) {
console.log(n);
}
}
// This will output nothing because all the members belong to the prototype.
// If I remove the hasOwnProperty check then 'name' and 'age' will be output.
Is my understanding correct that the difference only becomes apparent when testing for members on the object itself?
Your assumptions are correct, but there is another pattern that Douglas doesn't talk much about - the prototype can be used for properties as well. Your person class could have been written as:
var Person = function(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.name = null; //default value if you don't init in ctor
Person.prototype.age = null;
Person.prototype.gender = "male";
Person.prototype.toString = function(){return this.name + ', ' + this.age;};
In this case, iterating over properties of an instance of this class, as you do in your example, would generate no output for the 'gender' property.
EDIT 1:
The assignment of name and age in the constructor do make the properties visible by hasOwnProperty (thanks #matt for reminding me of this). The unassigned gender property would not be visible until someone sets it on the instance.
EDIT 2:
To further add to this, I present an alternative inheritance pattern - one that I have personally used for very large projects:
var inherits = function(childCtor, parentCtor) {
function tempCtor() {};
tempCtor.prototype = parentCtor.prototype;
childCtor.superclass = parentCtor.prototype;
childCtor.prototype = new tempCtor();
childCtor.prototype.constructor = childCtor;
};
var Person = function(name){
this.name = name;
}
Person.prototype.name = "";
Person.prototype.toString = function(){
return "My name is " + this.name;
}
var OldPerson = function(name, age){
OldPerson.superclass.constructor.call(this);
this.age = age
};
inherits(OldPerson, Person);
OldPerson.prototype.age = 0;
OldPerson.prototype.toString = function(){
var oldString = OldPerson.superclass.toString.call(this);
return oldString + " and my age is " + this.age;
}
This is a fairly common pattern with a small twist - the parent class is attached to the child via the "superclass" property permitting you to access methods/properties overridden by the child. Technically, you could replace OldPerson.superclass with Person, however that is not ideal. If you ever changed OldPerson to inherit from a class other than Person, you would have to update all references to Person as well.
EDIT 3:
Just to bring this full circle, here is a version of the "inherits" function which takes advantage of Object.create and functions exactly the same as I previously described:
var inherits = function(childCtor, parentCtor) {
childCtor.prototype = Object.create(parentCtor.prototype);
childCtor.superclass = parentCtor.prototype;
};
EDIT: This answer was originally a response to #jordancpaul's answer, which he has since corrected. I will leave the portion of my answer that helps explain the important difference between prototype properties and instance properties:
In some cases, properties are shared between all instances and you need to be very careful whenever you're declaring properties on the prototype. Consider this example:
Person.prototype.favoriteColors = []; //Do not do this!
Now, if you create a new Person instance using either Object.create or new, it doesn't work as you might expect...
var jim = new Person("Jim",13);
jim.favoriteColors.push('red');
var tim = new Person("Tim",14);
tim.favoriteColors.push('blue');
console.log(tim.favoriteColors); //outputs an array containing red AND blue!
This doesn't mean you can't ever declare properties on the prototype, but if you do, you and every developer who works on your code needs to be aware of this pitfall. In a case like this, if you prefer declaring properties on the prototype for whatever reason, you could do:
Person.prototype.favoriteColors = null
And initialize it to an empty array in the constructor:
var Person = function(name, age) {
...
this.favoriteColors = [];
}
The general rule when using this method is that default values for simple literal properties (strings, numbers, booleans) can be set on the prototype directly, but any property that inherits from Object (including arrays and dates) should be set to null and then initialized in the constructor.
The safer way is to only declare methods on the prototype, and always declare properties in the constructor.
Anyway, the question was about Object.create...
The first argument passed to Object.create is set as the prototype of the new instance. A better usage would be:
var person = {
initialize: function(name, age) {
this.name = name;
this.age = age;
return this;
},
toString: function() {
return this.name + ', ' + this.age;
}
};
var tim = Object.create(person).initialize("Tim",14);
Now the output will be the same as in your first example.
As you can see, it's a different philosophical approach from the more classical style of OOP in Javascript. With Object.create, the emphasis is on creating new objects from existing objects, rather than on the constructor. Initialization then becomes a separate step.
Personally I have mixed feelings about the Object.create approach; it's very nice for inheritance because of the second parameter that you can use to add additional properties to an existing prototype, but it also is more verbose and makes it so instanceof checks no longer work (the alternative in this example would be to check person.isPrototypeOf(tim)).
The main reason I say Object.create is verbose is because of the second parameter, but there are some useful libraries out there that address that:
https://github.com/Gozala/selfish
https://github.com/Raynos/pd
(and others)
I hope that was more enlightening than confusing!

Can we call this real prototypal inheritance?

I'm always flabbergasted by the way people try to force some form of classical inheritance into javascript. I have designed a method to inherit in some object b the prototype methods from object a, without adding prototype methods from object b to object a, and the possibility to use private variables from the object inherited from1. Now I'm curious: would you say this is really prototypal 'inheritance'? Is it a viable method? Are there pittfals to it?
Here's some example code:
Object.prototype.inheritsFrom = function(obj){
var prototo = this.prototype,
protofrom = obj.prototype;
for (var l in protofrom) {
if (protofrom.hasOwnProperty(l)){
prototo[l] = protofrom[l];
}
}
}
function Obj1(){
var const1 = 25;
if (!Obj1.prototype.getConst1){
Obj1.prototype.getConst1 = function(){
return const1;
}
}
}
function Obj2(){
var const2 = 50;
if (!Obj2.prototype.getConst2){
Obj2.prototype.getConst2 = function(){
return const2;
}
}
Obj2.inheritsFrom(Obj1);
}
var instanceA = new Obj1,
instanceB = new Obj2;
Now instanceA contains method getConst1, instanceB contains methods getConst1 and getConst2, as you can see in this jsfiddle.
1 By assigning the prototype methods in the constructor function, effectively using the closure created by that.
No, that's not prototypical inheritance. In true prototypical inheritance, changes to the prototype appear in the objects that rely on that prototype. In your example, they don't, because they're only copied.
I'm not saying it may not be another useful form of inheritance for some situations, but it's not prototypical. In some sense I'm not even sure it's inheritance, although I think one could argue it either way and it doesn't really matter regardless.
Here's an example of adding to the prototype:
function Parent() {
}
Parent.prototype.foo = function() {
display("foo!");
};
function Child() {
}
Child.prototype = new Parent();
var c = new Child();
display("[before] typeof c.foo === '" + typeof c.foo + "'");
// shows "[before] typeof c.foo === 'function'"
display("[before] typeof c.bar === '" + typeof c.bar + "'");
// shows "[before] typeof c.bar === 'undefined'"
display("Note that c.bar is currently undefined");
Parent.prototype.bar = function() {
display("bar!");
};
display("[after] typeof c.bar === '" + typeof c.bar + "'");
// shows "[after] typeof c.bar === 'function'"
display("Now c.bar is a function");
c.foo();
c.bar();
Live copy
Note that this is not an obscure case. After all, your own code relies on changes to Object.prototype being reflected in the other things (Function) that have already derived from it.
Off-topic: Strongly recommend never adding anything to Object.prototype. It will break a huge amount of code that assumes that using for..in on a {} would yield no properties. Until you can reliably mark additions as non-enumerable (ECMAScript5 now provides a way to do that, but most implementations don't have it yet), just stay away from Object.prototype. Just a recommendation. Additionally, in your case, it doesn't make sense, because the inheritsFrom only works for Function instances, so you'd want to add it to Function.prototype instead (which is a lot less dangerous).

Categories