Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Object oriented javascript question

1 view
Skip to first unread message

Jeremy

unread,
Jul 15, 2010, 4:36:50 PM7/15/10
to
Hi, I'm trying to figure out how to modify the property of an object
from within an object descended from that parent object. Here's the
code:

//new object
function A() {
this.first = "one";
this.second = "two";
this.third = "three";
}

//add the 'typing' object to our object
A.prototype.myType = {
firstType : function() {

},
secondType : function() {
//how do I alter the value of function A's "second" property from
here?
// 'this' is scoped to the current object
},
thirdType : function() {

}
}

B = new A();

var typeIt = "secondType";

if (typeIt in B.myType) {
B.myType['typeIt'];
}

I want to change the value of A.second (well, once I invoke it as "B",
it will be B.second) to be something other than "two." The 'this'
keyword within A.myType references the myType object. How do I
reference this instance of A, however?

Thanks, in advance.

RobG

unread,
Jul 15, 2010, 7:48:11 PM7/15/10
to
On Jul 16, 6:36 am, Jeremy <jerb...@gmail.com> wrote:
> Hi, I'm trying to figure out how to modify the property of an object
> from within an object descended from that parent object. Here's the
> code:
>
> //new object
> function A() {
> this.first = "one";
> this.second = "two";
> this.third = "three";
> }

When A is called as a constructor, its this keyword is set as a
reference to a newly created object. Objects constructed using new A()
(which might be called instances of A) will each have properties
first, second and third with the values assigned above.


>
> //add the 'typing' object to our object
> A.prototype.myType = {

That doesn't add it to "our object", it creates a property called
myType on A.prototype and assigns it a reference to a new object.
Objects created from constructor A when it has this prototype object
will inherit the myType property.


> firstType : function() {
>
> },
> secondType : function() {
> //how do I alter the value of function A's "second" property from
> here?

Function A doesn't have a "second" property, so it is impossible to
modify it. It will create a "second" property of instances when called
with the new keyword.

What you have done is added a myType property to A.prototype and
assigned it a reference to an object with a secondType property that
is a function. To call it from an instance of A you'd need:

a_Instance.myType.secondType()


in which case, secondTypes's this keyword will be a reference to
myType (because that's how it's called). The simple solution is to add
the secondType function directly to A.prototype:

A.prototype.secondType = function(){...
A.prototype.thirdType = function(){...


Alternatively, replace A.prototype with the myType object. Since the
functions are setting values, I'd call them "set...":

A.prototype = {
setFirstType: function(value){
this.first = value;
},
setSecondType: function(value){
this.second = value;
},
setThirdType: function(value) {
this.third = value;
}
};

Note that if you adopt the second approach, it will only affect
instances of A created after the assignment. Instances created before
then will use the previous A.prototype.


> // 'this' is scoped to the current object

The value of a function's this keyword has nothing to do with scope.
Its value is completely under the control of the caller.


> },
> thirdType : function() {
> }
>
> }
>
> B = new A();

By convention, variable names starting with a capital letter are
reserved for constructors and constants (which are usually all
capitals).


> var typeIt = "secondType";
>
> if (typeIt in B.myType) {
> B.myType['typeIt'];
> }
>
> I want to change the value of A.second (well, once I invoke it as "B",
> it will be B.second)

There is no A.second, you want to change B.second.


> to be something other than "two." The 'this'
> keyword within A.myType references the myType object. How do I
> reference this instance of A, however?

There is no A.myType, nor is the myType property on A's prototype
chain. Property resolution proceeds through the internal [[prototype]]
property, which is (usually) a completely different set of objects to
the public prototype property.

Here's a full example:

function A() {
this.second = 'second';
}

A.prototype = {
setFirstType: function(value){
this.first = value;
},
setSecondType: function(value){
this.second = value;
},
setThirdType: function(value) {
this.third = value;
}
};

var anA = new A();

alert(anA.second); // shows 'second'

anA.setSecondType('new second type');

alert(anA.second); // shows 'new second type'


Of course you are changing public properties of instances, next you'll
want to know how to keep them private and only change them using
privileged functions (getters and setters). That's been covered here
too (and in various blogs). Come back when you're ready. :-)


--
Rob

Thomas 'PointedEars' Lahn

unread,
Jul 16, 2010, 10:10:28 AM7/16/10
to
RobG wrote:

Further, since the value of the `prototype' property would be a reference to
a newly created Object instance (through the Object initializer, `{'...`}'),
the inherited `constructor' property of the latter instances would be
`Object', not `A' anymore. This can be confusing. It is possible to add a
corresponding user-defined `constructor' property to `A.prototype', but by
contrast to the built-in `constructor' property it will be enumerable by
default. ECMAScript Edition 5 specifies the Object.defineProperty() and
Object.defineProperties() methods to define a non-enumerable property; they
are implemented in Google V8 since version 2.1 (Chrome 5.0.342) and Apple
JavaScriptCore since version 533.16 (Safari 4.0.4).

As an alternative, the original prototype object can be kept and just
augmented with properties. A way to do this is for-in iteration:

var o = a_Instance.myType;
for (var p in o)
{
A.prototype[p] = o[p];
}

Note that a *shallow* copy of all *enumerable* properties, including
inherited ones, of the object referred to by `o' will be created. If only
own enumerable properties should be copied, the o.hasOwnProperty() method
can be used.

>> var typeIt = "secondType";
>>
>> if (typeIt in B.myType) {
>> B.myType['typeIt'];
>> }
>>
>> I want to change the value of A.second (well, once I invoke it as "B",
>> it will be B.second)
>
> There is no A.second, you want to change B.second.

And remove the apostrophes around `typeIt', else the name of the accessed
property would be `typeIt', not `secondType'. But it would still have no
overly useful effect.


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16

kangax

unread,
Jul 16, 2010, 7:14:25 PM7/16/10
to
On 7/16/10 10:10 AM, Thomas 'PointedEars' Lahn wrote:
> RobG wrote:
[...]

>> Note that if you adopt the second approach, it will only affect
>> instances of A created after the assignment. Instances created before
>> then will use the previous A.prototype.
>
> Further, since the value of the `prototype' property would be a reference to
> a newly created Object instance (through the Object initializer, `{'...`}'),
> the inherited `constructor' property of the latter instances would be
> `Object', not `A' anymore. This can be confusing. It is possible to add a
> corresponding user-defined `constructor' property to `A.prototype', but by
> contrast to the built-in `constructor' property it will be enumerable by
> default. ECMAScript Edition 5 specifies the Object.defineProperty() and
> Object.defineProperties() methods to define a non-enumerable property; they
> are implemented in Google V8 since version 2.1 (Chrome 5.0.342) and Apple
> JavaScriptCore since version 533.16 (Safari 4.0.4).
^^^^^

That should be Safari 5, not 4.0.4 (build number is right, though).

Also see <http://kangax.github.com/es5-compat-table/>

[...]

--
kangax

Thomas 'PointedEars' Lahn

unread,
Jul 16, 2010, 7:31:54 PM7/16/10
to
kangax wrote:

> Thomas 'PointedEars' Lahn wrote:
>> RobG wrote:
> [...]

>> ECMAScript Edition 5 specifies the Object.defineProperty() and
>> Object.defineProperties() methods to define a non-enumerable property;
>> they are implemented in Google V8 since version 2.1 (Chrome 5.0.342) and
>> Apple JavaScriptCore since version 533.16 (Safari 4.0.4).
> ^^^^^
>
> That should be Safari 5, not 4.0.4 (build number is right, though).
>
> Also see <http://kangax.github.com/es5-compat-table/>

No. As a matter of fact, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)
AppleWebKit/533.16 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"
supports both Object.defineProperty() and Object.defineProperties().

kangax

unread,
Jul 16, 2010, 7:44:46 PM7/16/10
to
On 7/16/10 7:31 PM, Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
>
>> Thomas 'PointedEars' Lahn wrote:
>>> RobG wrote:
>> [...]
>>> ECMAScript Edition 5 specifies the Object.defineProperty() and
>>> Object.defineProperties() methods to define a non-enumerable property;
>>> they are implemented in Google V8 since version 2.1 (Chrome 5.0.342) and
>>> Apple JavaScriptCore since version 533.16 (Safari 4.0.4).
>> ^^^^^
>>
>> That should be Safari 5, not 4.0.4 (build number is right, though).
>>
>> Also see<http://kangax.github.com/es5-compat-table/>
>
> No. As a matter of fact, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US)
> AppleWebKit/533.16 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"
> supports both Object.defineProperty() and Object.defineProperties().

Interesting...

My Safari 4.0.5 [1] on Mac OS X has neither `Object.defineProperty` nor
`Object.defineProperties`; Safari 5 [2] has both.

[1] Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us)
AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7

[2] Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us)
AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16

I don't understand how your 4.0.4 ended up with 533.x webkit build.

Can anyone else confirm?

--
kangax

Thomas 'PointedEars' Lahn

unread,
Jul 16, 2010, 8:31:05 PM7/16/10
to
kangax wrote:

JFTR: I had the older version before, but thought it was an error to be
corrected. (So I did. D'oh.)

Now that you pointed out the version mismatch too, I came to suspect that it
was because I had installed Safari 5.0 in the same Wine subtree. Since I
suddenly had problems running any Safari browser tonight (which might have
to do with a winecfg on the wrong subtree), I have just reinstalled version
4.0.4 again into a clean subtree, and you are right:

"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/531.21.8
(KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" does not support
Object.defineProperty() or Object.defineProperties(). (See the tests
below.)

Thank you. (Note to self: Always install a Safari version into its own Wine
subtree.)

It would appear that I have to double-check all JavaScriptCore test results
for the ECMAScript Support Matrix¹ so far. BTW, those are tests for
functionality, and will be available with the next revision of the Matrix.
As a preview, for those two methods they currently are (PHP code cleaned,
pretty-printed):

var o = new Object(),
b = isMethod(Object, 'defineProperty')
&& Object.defineProperty(o, 'a', {
value: {b: 'c'},
writable: false,
configurable: false,
enumerable: false
})
&& (typeof o.a == 'object') && o.a
&& (o.a.b == 'c')
&& (o.a = 42) && (o.a != 42);
delete o.a;
b = b && (typeof o.a != 'undefined');
if (b)
{
var found = false;


for (var p in o)
{

if (p == 'a')
{
found = true;
break;
}
}
}
b && !found;

and

var o = new Object(),
b = isMethod(Object, 'defineProperties')
&& Object.defineProperties(o, {
a: {
value: {b: 'c'},
writable: false,
configurable: false,
enumerable: false
},
b: {
value: {c: 'd'},
writable: false,
configurable: false,
enumerable: false
}
})
&& (typeof o.a == 'object') && o.a
&& (o.a.b == 'c')
&& (o.a = 42) && (o.a != 42)
&& (typeof o.b == 'object') && o.b
&& (o.b.c == 'd')
&& (o.b = 42) && (o.b != 42);
delete o.a;
delete o.b;
b = b && (typeof o.a != 'undefined') && (typeof o.b != 'undefined');
if (b)
{
var found = false;


for (var p in o)
{

if (p == 'a' || p == 'b')
{
found = true;
break;
}
}
}
b && !found;

The result of either program determines if the corresponding feature is
considered to be supported by an implementation. A true-value indicates
that it is supported, a false-value that it is not.

AFAICS, the tests are only incomplete in that they do not test that the
attributes of a property that does not have the [[Configurable]] attribute
set must not be possible to redefine with Object.defineProperty() (except of
its value).

Suggestions welcome.

PointedEars
___________
¹ <http://PointedEars.de/es-matrix>

kangax

unread,
Jul 18, 2010, 8:55:44 AM7/18/10
to
On 7/16/10 8:31 PM, Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
[...]

>> My Safari 4.0.5 [1] on Mac OS X has neither `Object.defineProperty` nor
>> `Object.defineProperties`; Safari 5 [2] has both.
>>
>> [1] Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us)
>> AppleWebKit/531.22.7 (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7
>>
>> [2] Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us)
>> AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16
>>
>> I don't understand how your 4.0.4 ended up with 533.x webkit build.
>
> JFTR: I had the older version before, but thought it was an error to be
> corrected. (So I did. D'oh.)
>
> Now that you pointed out the version mismatch too, I came to suspect that it
> was because I had installed Safari 5.0 in the same Wine subtree. Since I
> suddenly had problems running any Safari browser tonight (which might have
> to do with a winecfg on the wrong subtree), I have just reinstalled version
> 4.0.4 again into a clean subtree, and you are right:
>
> "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/531.21.8
> (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10" does not support
> Object.defineProperty() or Object.defineProperties(). (See the tests
> below.)
>
> Thank you. (Note to self: Always install a Safari version into its own Wine
> subtree.)

No problem. You got me worried there for a bit.

>
> It would appear that I have to double-check all JavaScriptCore test results
> for the ECMAScript Support Matrix¹ so far. BTW, those are tests for
> functionality, and will be available with the next revision of the Matrix.
> As a preview, for those two methods they currently are (PHP code cleaned,
> pretty-printed):
>
> var o = new Object(),
> b = isMethod(Object, 'defineProperty')
> && Object.defineProperty(o, 'a', {
> value: {b: 'c'},
> writable: false,

^^^^^
> configurable: false,
^^^^^
> enumerable: false
^^^^^
> })

Technically, those are default values, so explicitly setting them is
redundant (although adds to clarity).

> && (typeof o.a == 'object')&& o.a


> && (o.a.b == 'c')

> && (o.a = 42)&& (o.a != 42);
> delete o.a;
> b = b&& (typeof o.a != 'undefined');


> if (b)
> {
> var found = false;
> for (var p in o)
> {
> if (p == 'a')

Maybe add `hasOwnProperty` check too?

> {
> found = true;
> break;
> }
> }
> }
> b&& !found;
>

[snip defineProperties test]

>
> The result of either program determines if the corresponding feature is
> considered to be supported by an implementation. A true-value indicates
> that it is supported, a false-value that it is not.
>
> AFAICS, the tests are only incomplete in that they do not test that the
> attributes of a property that does not have the [[Configurable]] attribute
> set must not be possible to redefine with Object.defineProperty() (except of
> its value).

Well if we're talking about full conformance, then there are also no
tests for `Object.defineProperty` throwing TypeError when first argument
is not an object; no test for getters/setters (i.e. "get" and "set"
properties in object corresponding to property descriptor); no test for
ToPropertyDescriptor which is invoked during `defineProperty` and is,
for example, responsible for throwing TypeError when you pass an object
that can not be either data descriptor or accessor one:

Object.defineProperty({}, 'x', { value: 'y', set: function(){} });
// or
Object.defineProperty({}, 'x', { get: function(){}, writable: true });

But then it might make sense to just look into relevant section of ES5
test suite on codeplex (https://es5conform.codeplex.com/).

[...]

--
kangax

0 new messages