PLS PLS PLS explain what a prototype is

I thought a prototype was a sort of “proto” object or something, but it turns out it’s just a property?

I’m confused… why is inheritance such a big deal with JS? (how does inheritance in JS differ from inheritance in Java?)
(I know all JS objects inherit from a sort of primal, “mother” Object… I used to think this “mother” object was the same as a prototype… now of course I’m realizing I’m wrong…:wink:

the reason am looking at this now is that I’ve been learning a lot of JSON lately (and thanks to help from fellow developers right here on SP I have learned a lot, and am finally comfy with JSON – yay!)

but I still have “lose ends”…:wink:

such as: how do you list the KEYS of an object in plain Javascript?

in jQuery it’s so simple, as you pass both the key and the value to the $.each() method; in plain, in this loop…

 for (var i in data.users) 

what exactly is “i”?? just the index of the kay-value pair, right?

something like

 data.users[i].firstName  

prints the value of the key “firstName”, but how do I print the KEY?

I’ve been reading up on this here…
http://stackoverflow.com/questions/208016/how-to-list-the-properties-of-a-javascript-object
(hence my q’s about prototypes…:wink:

I frankly don’t get any of the examples, tried a few, none worked…

I’m printing values thus:

  
for (var i in data.users) {
     output+="<li>" + data.users[i].firstName + " " + data.users[i].lastName + " -- " + data.users[i].joined.month+"</li>";
     }

so how do I do something like

  
for (var i in data.users) {
     output+="<li>" + data.users[i].KEY"</li>";
     }

???

I can’t believe how hard this is compared to the beauty of the jQuery $.each() method…:-o

meaning:


$.each(val, function(propName,propValue) {	
	divLeft.append(propName + '<br>');
});

and voila!! no fuss no muss…:wink:

thank you… HAPPY FOURTH OF JULY…

thank you…

The for…in construct is for looping over all the properties of an object. For each property of the object, the property name (or key, if you prefer) is assigned to the variable you supply (prop, in the example below). You can use this to access the property’s value using the array syntax: object[key]. Here’s an example:

var myObj = {
    name: "Steve Jobs",
    company: "Apple",
    email: "sjobs@apple.com"
}

for (var prop in myObj) {
    if( myObj.hasOwnProperty( prop ) ) {
        console.log(prop + " = " + myObj[prop]);
    } 
}

this would output:


name = Steve Jobs
company = Apple
email = sjobs@apple.com 

The hasOwnProperty check ensures that we’re only iterating the properties of the object and not the object’s prototype.

In Java (as in PHP) you create a class as a ‘template’ for creating new objects, and your classes can inherit from other classes. JavaScript doesn’t have the concept of a class. If you want ObjectB to inherit methods and properties from ObjectA, you have to set Object A as the prototype for ObjectB.

Here’s an example:

var Employee = function(name) {
    this.name = name;

    this.getName = function () {
        return this.name;
    }

    return this;
};

var Manager = function(name, department) {
    Employee.apply(this, arguments);

    this.department = department;
    
    this.getDepartment = function () {
        return this.department;
    }

    return this;
};

Manager.prototype = new Employee();

var dave = new Manager('Dave', 'Frozen Goods');

console.log(dave.getName() + ' manages ' + dave.getDepartment);
// Outputs: Dave manages Frozen Goods

Edit: When you try to access a method or property on an object, if it can’t be found then JavaScript looks at the object’s prototype to see if it can find them there, and so on and so on, back up the prototype-chain.

Something that’s helpful to note is that prototypical structures can simulate what classes do, but not the other way around. Classes can’t do what prototyping does, so prototyping is more flexible than classes.

Basically all object contain a prototype and a constructor. The prototype is a set of properties (you could call them default values) that exist on those created objects, and the constructor is a function that runs when a new object is created. Also, each object has a hidden reference to a parent prototype, which is what you alluded to earlier.

I find though that an image can help to replace a thousand words. The following guide on JavaScript object is a must-read, with good information and diagrams helping to explain what prototypes are.
http://mckoss.com/jscript/object.htm

Manager.prototype = new Employee();

???

oh my gosh, I have never seen this (until today, when I saw in some of the S.O. urls I looked at…)

wouldn’t something like

Manager = new Employee() 

???

make “Manager” inherit from Employee?

like in this example…

function Employee() {
	this.dept = "HR";
	this.manager = "John Johnson";
}

var Jon = new Employee();
     console.log(Jon.manager);

Jon inherits from Employee, right?

oh brother…

also, thank you for the obj code you posted for grabbing obj keys…

I don’t know why, but in my thingie this code prints this:

1 = [object Object]

my code:


list = data.users;

for (var prop in list) {
	if( list.hasOwnProperty( prop ) ) {
		$('#console').append(prop + " = " + list[prop]);
	} 
}			

this other code

 data.users[i].firstName  

prints the value fine…

thank you very much for your response…

That would make Manager a new instance of Employee. If you mean:

Manager.prototype = new Employee();

Then what I’m doing is saying that I want Manager objects to have access to the methods and properties of Employee (after all, a manager is a type of employee too).

No, Jon IS an Employee - the variable Jon holds an object of the type Employee.

In this case, users is an array of objects - if you wanted to iterate the properties of those object you need to nest that inside a loop which iterates over the array, something like this:

var length = data.users.length;
for(var i = 0; i < length; i++) {
    var user = data.users[i]
    for (var prop in user) {
	if( list.hasOwnProperty( prop ) ) {
		console.log(prop + " = " + user[prop]);
	} 
    }
}

Something that’s helpful to note is that prototypical structures can simulate what classes do, but not the other way around. Classes can’t do what prototyping does, so prototyping is more flexible than classes.

Basically all object contain a prototype and a constructor. The prototype is a set of properties (you could call them default values) that exist on those created objects, and the constructor is a function that runs when a new object is created. Also, each object has a hidden reference to a parent prototype, which is what you alluded to earlier.

I find though that an image can help to replace a thousand words. The following guide on JavaScript object is a must-read, with good information and diagrams helping to explain what prototypes are.

thank you Paul… I guess I hadn’t seen your comment when I posted my previous response…

ok, so a prototype is a set of default key-value pairs that… all objects you create in JavaScript have (I mean objs you create in classic fn syntax) ?? I suppose these are inherited when you create an instant of this object with the keyword “new”??)

so a “prototype” is just this set of default key-value pairs? like local variables in a Java class…??
(oooopsss… that would be class variable, as in Java there are no local vars in classes, only in methods… hmmmm…:wink:

I still don’t know what you mean by “parent prototype”… parent of what? prototype is just a list of properties and values… why don’t we just call them default properties or something? (in Java classes they’re also referred to as properties (as long as they’re static, I suppose…:wink:
(and are these default key-value pairs inside the constructor or outside it? (& what are they??? :wink: what are these default key-value pairs? is there a list of them? :wink:

thank you very much for all your help these last few days, Paul… I really appreciate it…
(with JSON you have no choice but dig into OO… I still find it a bit hard… not all of it, but some aspects of it… (I find it harder than Java OOP…)

and thank you for the url you posted… I will read it tomorrow…

have a good day…

JavaScript is a prototyping language whereas Java is an object oriented one. Since OO is far more limited than prototyping you can’t replicate the prototype structuring in JavaScript in any OO language.

The Object.create() method was recently introduced into Javascript to simplify the way that inheritence is applied. It allows you to do in one statement what used to take four or five.

Very interesting article Paul, thanks for sharing. Every time I read another article about prototypes I learn something new!

thank you fretburner… but this still doesn’t print… :frowning:
(and I don’t get an error…)

but I see what you’re saying, I had to loop down one more level to get the list of keys for each user…

so when you do this,

 for (var prop in user) {  

how does JS know if ‘prop’ is the KEY or the VALUE?

thank you very much for your help…

oh my gosh, that’s right… I was thinking of when you extend a class in Java… of course it’s not the same as instantiating a class… oh brother…

well, instead of bugging you guys any more I will read the url Paul posted yesterday, that you also said was very good…:slight_smile:

thank you all very much for your help…

There are a couple problems with your JS:

for (var prop in user) {
    if( list.hasOwnProperty( prop ) ) {
        $('content').html(prop + " = " + user[prop]);
    } 
}
  • You’re checking if list.hasOwnProperty but you want to be checking the user object.
  • You’re missing the hash (id) symbol from your jQuery selector - it should be $('#content')
  • You probably want to be calling .append rather than .html, otherwise you’ll only see the last property displayed

It’s just the way that particular construct works, it iterates over keys/property names.

oh my gosh… two stupid mistakes… ::blush:

it finally works now:slight_smile:

(and, just like you said, I changed that “list” to “user” in there…)

now I have to loop thru the “joined” obj, since that one contains key-val pairs…

(bottom line with JSON: when you’re looping thru an array, if element you encounter is an object instead of a value you need to stop and loop thru the key-val pairs in that object… yes? I find this quite easy in jQuery, now learning how to do “the old-fashioned” way…:slight_smile:

once again thank you very much for your help…

fretburner,

I have another question…

[quote] how does JS know if ‘prop’ is the KEY or the VALUE?

It’s just the way that particular construct works, it iterates over keys/property names.[/QUOTE]

so in code like this (which I found online)



  var output="<ul>";
        for (var i in data.users) {
            output+="<li>" + data.users[i].firstName + " " + data.users[i].lastName + " -- " + data.users[i].joined.month+"</li>";
        }

“i” is the KEY (isn’t it being used as the index here? not the KEY?)

thanks again…

You could use a recursion to do this:

function iterateProperties(obj) {
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            if (typeof obj[property] == "object")
                iterate(obj[property]);
            else
                $('#content').append(prop + " = " + obj[prop] + '<br>');
        }
    }
}

var length = data.users.length;
for(var i = 0; i < length; i++) {
    var user = data.users[i]
    iterateProperties(user);
    $('#content').append('<br>');
}

It will loop through all the properties and output all the strings. If it finds a nested object, it repeats the process for that object.

Yes, I can see where your confusion lies. It’s confusing because for…in is bad for iterating over an array. There are technical reasons, and ideological reasons for that, - which we can get in to if you want to delve more deeply in to that.

The for…in code is less confusing when it uses key instead of i, because a variable called key more closely represents what a for…in loop is supposed to be used for - to loop over the keys of an object.


var output = ...,
    key;
for (key in data.users) {
    ...
}

The name of the variable is of no importance to JavaScript. The name is to help the programmer to more easily understand the intention of the code.

When using a variable called key, it is expected that it will be for an object that contains differently named keys, for example:


var myObj = {
    name: "Steve Jobs",
    company: "Apple",
    email: "sjobs@apple.com"
}

So when iterating through that object, the variable called key will contain a string value of “name” and then “company” and lastly “email”.
When using a variable called i, it is expected that the variable will be a numbered index for an array.

In your particular situation, data.users is not an object - it’s an array instead. Arrays are not to be processed using for…in.

The upshot though is - loop through an array and process it using a normal for loop, or use other more specialised [URL=“https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Iteration_methods”]iteration methods for arrays. Reserve the use of for…in for when processing non-array objects.

Here is how you should loop through the data.users array:


var output = "<ul>",
    i;
for (i  = 0; i < data.users.length; i += 1) {
    output += "<li>" + data.users[i].firstName + " " + data.users[i].lastName + " -- " + data.users[i].joined.month + "</li>";
}

You could also use the forEach method to process array items:


var output = "<ul>";
data.users.forEach(function (item, index) {
    output += "<li>" + data.users[index].firstName + " " + data.users[index].lastName + " -- " + data.users[index].joined.month + "</li>";
}

The index doesn’t have to be used though. It is better to use the array’s item that’s passed to the function instead:


var output="<ul>";
data.users.forEach(function (item, index) {
    output += "<li>" + item.firstName + " " + item.lastName + " -- " + item.joined.month + "</li>";
}

Because we’re not even using the index variable now, we can remove that from the function parameters:


var output="<ul>";
data.users.forEach(function (item) {
    output += "<li>" + item.firstName + " " + item.lastName + " -- " + item.joined.month + "</li>";
}

“item” can also be renamed to “user”, to make things easier for us to understand what the function is doing:


var output="<ul>";
data.users.forEach(function (user) {
    output += "<li>" + user.firstName + " " + user.lastName + " -- " + user.joined.month + "</li>";
}

We could also use the reduce method instead. It start with the string that we give it as the second argument, and it runs the function for each item in the array, each time adding more content on to the string.


var output = data.users.reduce(function (str, user) {
    return str + "<li>" + user.firstName + " " + user.lastName + " -- " + user.joined.month + "</li>";
}, "<ul>");

So in summary, techniques that are designed to handle arrays, are the best ways of dealing with arrays.

oh brother… now get error:

 iterate is not defined 

???

(I put the fn decl outside $(document).ready(function() {} this where you’re supposed to to put fn declarations…)

again, thank you very much…

Oops, sorry, my fault…

function iterateProperties(obj) {
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            if (typeof obj[property] == "object")
                iterateProperties(obj[property]); // This line changed
            else
                $('#content').append(prop + " = " + obj[prop] + '<br>');
        }
    }
}

I changed the name of the function from iterate to iterateProperties, but I missed the call from inside the function itself.

awesome!! :slight_smile:

thank you!!

(I did have to chg “prop” to “property” in the print statement…:wink:
(at least I was able to catch that…:wink:

I really appreciate your help…

so I also wanted to print the info like it’s here, so I had to nest the looping, like I did on this page…

so I did this

and another in which for the nested object (“joined”) I printed props & values instead of just values…

this is so much easier in jQuery (& a lot less code also), but I need to know how to do this in plain JS also…

so is my code cool in those two examples? :slight_smile:

one again, thank you very much for your help…

The only piece in that iterateProperties function is the $(‘Content’) line, which can be easily changed in to normal JavaScript:


document.querySelector('#content').innerHTML += (prop + " = " + obj[prop] + '<br>');