From: nick on 17 Jan 2010 13:58 On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> wrote: .... > - $-prefixed property names are a problem for many reasons; avoid them > as recommended by Edition 3 Final of the (ECMAScript) Specification. Ok, I just had a look through a pdf document I found on mozzila's (sorry, web) site titled Edition 3 Final ECMAScript Language Specification: http://www.mozilla.org/js/language/E262-3.pdf Did a ctrl-f for "$" and "dollar," the only thing I see about it (besides some stuff about string matching and regular expressions) is: ## This standard specifies one departure from the grammar given in the Unicode standard: The dollar sign ($) and the underscore (_) are permitted anywhere in an identifier. The dollar sign is intended for use only in mechanically generated code. ## .... I didn't see where it recommended avoiding them, am I looking at the wrong document? -- Nick
From: Garrett Smith on 17 Jan 2010 14:19 nick wrote: > On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> > wrote: >> nick wrote: [...] > Object.prototype.$ = function(memberName) [...] > ...does that look any better? > No. Identifier `$` has no meaningful value. Modifying object.prototype breaks for-in loops. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Thomas 'PointedEars' Lahn on 17 Jan 2010 14:18 nick wrote: > Thomas 'PointedEars' Lahn wrote: > [...] > // Get mutable object from primitive value, or a reference > // to an object member if memberName is provided. > Object.prototype.$ = function(memberName) > { > if (!memberName) > return Object(this); > v = function() { return this.$_object[this.$_member] }; > return {$_object:this, $_member:memberName, valueOf:v, toString:v}; > }; > > // Set the value of current object. > Object.prototype.$_ = function(value) > { > if (this.$_object) > this.$_object[this.$_member] = value; > else > this.valueOf = this.toString = function() { return value }; > return this; > }; > > ## > > Alright, let me try to address some of your points. > > [...] >> - You want to avoid augmenting Object.prototype. > > I'm not sure I do. How else will I be able to do things like this: > > var foo = document.body.style.$('backgroundcolor'); Bad inference. The `style' property of those objects does _not_ refer to a native object (but to a host object), so you cannot expect it to inherit from Object.prototype or be extensible. > foo.$_('red'); // background of page turns red No, it will not. Not least because the correct property name is `backgroundColor'. > document.body.style.backgroundcolor = 'black'; > // value of foo is now 'black' Nobody wants to do that. Think of the performance penalty when calling a prototype method -- and for what? >> - Objects have identity, not name. > > Where did I say objects had names? Are you referring to this: > > "The '$' method will accept a single string parameter. If present, the > returned value will be a special reference to the named object member. > The result will appear to be a simple value, but it is linked with the > object member." > > I meant here that the member of the object is named, not that the > object is named. The reference is to the member, not the object. Do not let yourself be confused by the term `MemberExpression' in the Specification: those are _not_ members, they are _properties_ (the term "member" is only use for members of built-in *data types* in the Specification). Properties can hold values. If they hold references to objects (which are values), then that referred object has identity, not name: it can be referred to by properties of different name of different objects. However, you are false assuming that an object can only ever be referred to by the same property, as your wrapper object has a property to store only that one property's name. >> - You can only ever consider global variables or other properties >> of the Global Object with this, as the Activation Object of >> local execution contexts cannot be referred to. > > Can you clarify? I don't understand this. I think I was mistaken; `this' does not refer to an Activation Object here. However, the `$_object' property (regardless of its name) does not make sense except as a marker because its value is a reference to the calling object (`this'): this.$_object[this.$_member] === this[this.$_member]. BTW, there's another potential problem: You try to the augment the instance with a property `$_member', a property that becomes enumerable when set, and error-prone to rely on when not set. The supposed-to-be type-cast `Object(this)' is also pointless because in the context in which it is used, `this' is already a reference to an object; or, IOW, `this' *always* refers to an object (for primitive values: due to the built-in wrapping object) and does not need to be type-casted (provided that was possible so easily). Incidentally, when the Object() function is called as a function or a constructor with an object reference as argument, it simply returns that reference without creating a new object (ES3/5, 15.2.1.1 and 15.2.2.1). >> - toString() should return a primitive string value. > > I'd expect it to with this code. Are you suggesting I force the result > to a primitive? You better do, for which you would need to backup the original toString() method. >> - The modification does not work transparently; all code would >> need to be rewritten -- to be considerably less efficient afterwards. > > How could it possible work transparently, See my example. All that is additionally required then is defining a setter (with Object.protoype.__defineSetter__ and the like; not fully compatible, though); but then one could have used native setters and getters to begin with. > as the language doesn't support any concept of pointers? Non sequitur. > Using this would require rewriting all code, it just requires: (1) wrap > primitive in an object so you can use the $_() setter, and (2) use the > $_() setter to set a value when you want to modify the value "by > reference." And it would require rewriting of all functions and methods that used the wrapper object instead of the primitive value. Even though they only required read access. >> - Concept error: Nobody sane would not want to *modify* *constants*. > > Where did I modify constants? Not sure what you mean here either. `5' is a constant as is `"foo"'. Constant as in immutable. One would not attempt to modify immutable values, or emulate that by keeping a wrapper object to store another value. There is no advantage in doing that over working with the primitive value, and there are several possible disadvantages, some of which I have mentioned. So it remains a nice idea, good for theoretical discussion what is possible, but not a practical one. > Here's a modified snippet.... > [...] > ...does that look any better? Hardly. Please learn to quote; trim your quotes to the relevant parts. <http://jibbering.com/faq/#posting> pp. PointedEars -- Use any version of Microsoft Frontpage to create your site. (This won't prevent people from viewing your source, but no one will want to steal it.) -- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: nick on 17 Jan 2010 14:43 On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> wrote: .... > ECMAScript has built-in objects for most primitive types already that are > automatically used as wrapper objects and can do what you want. You could > augment *their* prototypes instead: > > Number.prototype._setValueOf = function() { > var v = this.valueOf(); > Number.prototype.valueOf = function() { > return (typeof this.value != "undefined") ? this.value : v; > }; > }; > > Number.prototype.plus = function(operand) { > this._setValueOf(); > this.value = this + operand; > return this; > }; > > var x = (2).plus(3); > x.plus(1); > > But probably this is not a particularly good idea either. Overriding Number instead of Object seems like a worse solution to me. It doesn't work as you might expect: ## Number.prototype._set = function(value) { var v = value.valueOf(); this.valueOf = this.toString = function() { return v; }; return this; }; function square(num) { num._set( num * num ); } var a = 5; square(a); alert(a); // shows 5 -- as expected var b = new Number(5); square(b); alert(b); // shows 25 -- this works var c = Object(5); square(c); alert(c); // shows 25 -- this works var d = [5]; square(d); // error: num._set is not a function alert(d); ## So, it looks like c was automatically converted to a Number, but d was not... not what I expected! Compare to this: ## // Set the value of current object. Object.prototype._set = function(value) { var v = value.valueOf(); this.valueOf = this.toString = function() { return v; }; return this; }; function square(num) { num._set( num * num ); } var a = 5; square(a); alert(a); // shows 5 -- as expected var b = new Number(5); square(b); alert(b); // shows 25 -- this still works var c = Object(5); square(c); alert(c); // shows 25 -- this still works var d = [5]; square(d); alert(d); // shows 25 -- this *works* ## Now we can use nice short object wrappers like [5] or ["blue"] and this will work ... not to mention I don't have to mess with String now, and any other primitive types I forgot about. -- Nick PS: sorry for atrocious spelling of Mozilla in previous post. PPS: sorry for triple post ;)
From: nick on 17 Jan 2010 15:39 On Jan 17, 2:18 pm, Thomas 'PointedEars' Lahn <PointedE...(a)web.de> wrote: > >> - You want to avoid augmenting Object.prototype. > > > I'm not sure I do. How else will I be able to do things like this: > > > var foo = document.body.style.$('backgroundcolor'); > > Bad inference. The `style' property of those objects does _not_ refer to a > native object (but to a host object), so you cannot expect it to inherit > from Object.prototype or be extensible. Sure, but it works in every browser I've tested it in, and not just for 'style,' so it seems consistent and useful... > > > foo.$_('red'); // background of page turns red > > No, it will not. Not least because the correct property name is > `backgroundColor'. > Touche ;) > ... you are false assuming that an object can only ever be > referred to by the same property, as your wrapper object has a property to > store only that one property's name. I don't really see the problem here... even if the object is referred to by other properties, my wrapper object only needs to know one way to find it in order to modify and read its value. In other words, var bob = {name:'bob', age:33}; var bobsDad = {son:bob, rel:'dad'}; var bobsKid = {dad:bob, rel:'son'}; var p = bobsDad.son.$('age'); p.$_(p + 10); alert (bobsKid.dad.age); // shows 43 > However, the `$_object' property (regardless of its name) does not make > sense except as a marker because its value is a reference to the calling > object (`this'): this.$_object[this.$_member] === this[this.$_member]. Good point, don't know how I missed that! > BTW, there's another potential problem: You try to the augment the instance > with a property `$_member', a property that becomes enumerable when set, > and error-prone to rely on when not set. Ew, missed that too... so that's why I'm not supposed to modify Object's prototype. > > The supposed-to-be type-cast `Object(this)' is also pointless because in > the context in which it is used, `this' is already a reference to an > object; or, IOW, `this' *always* refers to an object (for primitive values: > due to the built-in wrapping object) and does not need to be type-casted > (provided that was possible so easily). Incidentally, when the Object() > function is called as a function or a constructor with an object reference > as argument, it simply returns that reference without creating a new object > (ES3/5, 15.2.1.1 and 15.2.2.1). I read that somewhere too, and originally I just had "return this;" ... however it doesn't work in Google Chrome (beta 4 at least). Using the Object() function gives the expected result there. Simply returning 'this' does seem to work in every other js implementation I've seen. > > > Using this would require rewriting all code, it just requires: (1) wrap > > primitive in an object so you can use the $_() setter, and (2) use the > > $_() setter to set a value when you want to modify the value "by > > reference." > > And it would require rewriting of all functions and methods that used the > wrapper object instead of the primitive value. Even though they only > required read access. > Wait, why? The wrapper object is treated as a primitive value by anything that expects a primitive value. > > Where did I modify constants? Not sure what you mean here either. > > `5' is a constant as is `"foo"'. Constant as in immutable. One would not > attempt to modify immutable values, or emulate that by keeping a wrapper > object to store another value. Yes, but [5] and ["foo"] are not constants ;) What if you wanted to do something like this (perfectly valid c++): ## #include <stdio.h> void square(int *n) { *n *= *n; } int main() { int i = 5; square(&i); printf("%i\n",i); // prints 25 return 0; } ## If I try to emulate that by doing something like the following, am I really trying to modify constants? ## function square(n) { n._set(n * n); } function main() { int i = [5]; square(i); alert(i); // prints 25 return 0; } ## -- Nick
|
Next
|
Last
Pages: 1 2 3 4 Prev: knowing what and when to feature test Next: iscontenteditable browser support |