These are very interesting approaches:
((person2||{}).address||{}).zip || "no zip"
((person || 0).address || 0).zip || 'no zip';
But I prefer the way Peter proposed by checking the property with a
function, like in other languages. It's quite more readable.
And I prefer not to write the properties again after checking them so a
quite similar approach were to write a method
like that:
var person = {address: {zip: 1234}},
person2 = {};
/**
* returns the property value or false if property does not exist.
*/
Object.prototype.hasCustomProperty = function( sProperty ) {
var arr = sProperty.split('.');
var result = this;
var i = 1;
var l = arr.length;
while ( l && (result = result[arr.shift()]) ){
if( i++ == l ) { return result; }
}
return false;
}
var zip;
if ( (zip = person2.hasCustomProperty("address.zip")) ){
console.log(zip);
}else{
console.log("nozip");
}
if ( (zip = person.hasCustomProperty("address.zip")) ){
console.log("Person has zip:", zip);
}
2011/2/19 Michael Haufe (TNO) <[email protected]>
> On Feb 18, 12:29 pm, Scott Sauyet <[email protected]> wrote:
> > (Just a quick note to say that if I read your tone correctly, you seem
> > to be offense to my comments.
>
> Not at all. No offense is taken.
>
> > I just want to say that although I
> > disagree here, I've seen many of your posts in cljs and hold a good
> > deal of respect for you. I just seem to use JS in a very different
> > way than you do.)
>
> I'm somewhat echoing the point Asen made earlier in this thread though
> the details may differ.
>
> Earlier you stated:
> "However the manner in which you choose to organize it is strongly
> influenced by your choice of language. "
> ...
> "You're right, if you're trying to code as though you were in a
> statically-typed language. JS certainly allows you to code in that
> manner. But IMHO that ignores the strengths of the language. "
>
> I'd like to add that this manner is also influenced heavily by common
> practice by the community for good or ill. The drum I'm beating is
> that coding in a pattern ~vaguely~ similar to what you'd see in a
> statically typed language does not have to take away from the
> "strengths" of the language.
>
>
> > Michael Haufe (TNO) wrote:
> > > Scott Sauyet wrote:
> > >> [ ... ] When I program in Javascript, I don't usually
> > >> think in terms of classes of objects, but in one-off objects that may
> > >> or may not have certain properties. One of the great things about the
> > >> language is the ability to add and remove arbitrary properties of
> > >> objects.
> >
> > > And if you want scalable code you'll change what terms you consider
> > > again. The "great things" about the language are also terrible things
> > > when dealing with scale, hence the large number of meta-object
> > > features introduced in ES5.
> >
> > I'm not sure what you consider scale.
>
> Any code-base too large to keep in your head at once.
>
> > My current project involves ~65
> > JS files with just over 20K lines of JS code. It's a single-page web
> > application, AJAX-heavy, with JS required to use it. (Not my
> > choice!) The main data configuration used per client is between 20KB
> > and 300KB, with an object count in the thousands or tens of
> > thousands, or in rare cases in the low hundreds of thousands, never in
> > the millions. The user base will be moderate, measuring in the tens
> > of thousands, but not hundreds of thousands or millions, and probably
> > not more than a few hundred simultaneous users. What sort of scale do
> > you think is required to make your suggestion necessary?
>
> Its not necessity as much as it is clarity and simplicity. To take a
> small modification the example earlier:
>
> var persons = [{address: {zip: 1234}}, {}];
>
> //persons is an array of objects whose structural rules are in the
> mind of the developer
>
> //the persons array could have been created anywhere so lets make sure
> we're actually getting
> //the data we expect
> persons.forEach(function(person){
> if(typeof person == "object"){
> if(typeof person.address == "object"){
> if(typeof person.zip == "number")
> print(person.zip);
> else
> print("No zip code or an invalid zip code")
> }
> //type error (doesn't seem to be a person object, or else the
> person object
> // address is missing/invalid)
> }
> //type error (object was expected)
>
> });
>
> Now obviously this is ludicrously verbose and JS developers don't code
> like this, they instead assume the data will probably be correct:
>
> var persons = [{address: {zip: 1234}}, {}];
>
> persons.forEach(function(person){
> if(person && person.address && person.address.zip)
> print(person.address.zip || "no zip");
> });
>
> As long as you can control the data in that array, you can be
> relatively certain that all will be well. But what if more moving
> parts are included? What if the persons array is created from a JSON
> file? What if not all persons are created equally? Does it matter if I
> mix and match persons of different roles? This is where the method of
> code organization starts to matter as the code size increases with
> features. As things progress and more exceptions and additions are
> made to the code, more and more checks get added and this second
> example slowly starts looking like the first. Sure, you could come up
> with creative ways to decorate the objects with new properties to
> sniff for type info, or use some library/language trickery to reduce
> the bloat (adding a new method or use nullable objects) but I believe
> that makes it much harder than it needs to be. So if you initially do
> what Asen and I suggest with constructors you could avoid some of this
> code bloat down the line:
>
> var persons = [new Person(new Address(1234)), new Person()];
>
> persons.forEach(function(person){
> if(!(person instanceof Person))
> //type error
> print(person.address.zip || "no zip")
> });
>
>
> > We do an awful lot with configuration object parameters to our
> > functions, merging them with default values where appropriate.
>
> I assume you mean:
>
> doSomething({ foo:1, bar:2 });
>
> Of course there is nothing wrong with this by itself, but if you start
> using multidimensional arguments or a long list of them I'd say this
> is also something that needs to be re-visited:
>
> doSomething({
> foo : 1,
> bar : 2,
> quux : 3,
> address : {
> zip : 1234,
> state : "TX",
> country : "USA"
> }
> })
>
> > But there are many cases when we simply branch on the existence of
> certain
> > properties in objects supplied. We haven't run into any issues except
> > for slightly less readable code than we might have if we had the sort
> > of static contract you discuss.
>
> A contract does not have to be static.
>
> > We have not introduced any general nested property access of the sort
> > suggested by Peter van der Zee, but we do have the equivalent for the
> > main data configuration object, which is simply a JSON-ified version
> > of an industry-standard XML
> > format in which many elements at various levels are optional. It
> > works as you might expect, a get of "path.to.property" returns null if
> > any of the nodes are missing. A set for the same path creates empty
> > objects for any of the missing nodes.
> >
> > We could of course create a data model of constructor functions for
> > every level of the data model, and hook them together in an
> > appropriate way. But in the last six months, we've already done three
> > updates to the structure of the data model to later versions of the
> > industry standard. This involved no changes to our core data-access
> > mechanism. Had we tried to work with such a data model, it would have
> > been substantially more work, and I can't see that it would have
> > gained us anything.
>
> I had a similar project some years ago and used something like this:
>
> var myConfig = Config(
> AppSettings(
> Key("DBConn", "..."),
> Key("FileName","...")
> ),
> OtherStuff(),
> ...
> )
>
> ...
>
> doStuff(myConfig);
>
> Its of course easy enough to treat something like that as an object
> but this approach made the semantics explicit and the enforcement much
> easier as it simply takes a single instanceof check to know what data
> I'm getting and what operations can act upon it.
>
> > >> [U]nless you're quite certain that no code has done the equivalent of
> >
> > >> delete person2.address,
> >
> > >> you still need something like that to ensure your code won't fail
> > >> horribly.
> >
> > > Object.seal(...)
> >
> > If you're fortunate enough to be working in an ES5 environment, or you
> > code these features yourself, and if no one is passing you an unsealed
> > clone of your object, and no one has set the `address` property to a
> > non-object value, then maybe you can count on this working. But there
> > are probably other cases too where it still won't work.
>
> With JS being the language that it is, one could shoot holes in most
> anything. But the use of more robust patterns obviously reduce the
> probability of running across unintentional issues.
>
> > >> The point is simply that JS is a class-free language. You can
> > >> simulate classes to some degree, but it's never an exact match with
> > >> what's available in class-based languages.
> >
> > > I don't recall saying anything about classes nor their simulation nor
> > > any feature that is necessarily shared with them. You seem to be
> > > trying to present a Straw man.
> >
> > Not intentionally, I assure you. So what is the point of introducing
> > the Person and Address constructor functions in your earlier message
> > if not to use them as the equivalent of class constructors? I thought
> > the whole point was the contract that every person would have an
> > address which would have a zip code. If that is the point, then how
> > does that differ from OO-style classes?
>
> Using that terminology comes with a lot of implications that are
> invalid, so I prefer to avoid the use of the term. I assumed you were
> trying to imply that I was trying to smuggle in some type of foreign
> language construct which is not the case. But the constructor pattern
> obviously serves a similar role to OO-classes which serves a similar
> role to some constructs you can see in some functional languages which
> is not a bad thing. I could go on but I don't want to stray to far
> from the subject of the thread.
>
> --
> To view archived discussions from the original JSMentors Mailman list:
> http://www.mail-archive.com/[email protected]/
>
> To search via a non-Google archive, visit here:
> http://www.mail-archive.com/[email protected]/
>
> To unsubscribe from this group, send email to
> [email protected]
>
--
To view archived discussions from the original JSMentors Mailman list:
http://www.mail-archive.com/[email protected]/
To search via a non-Google archive, visit here:
http://www.mail-archive.com/[email protected]/
To unsubscribe from this group, send email to
[email protected]