From: Jeremy on
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.
From: RobG on
On Jul 16, 6:36 am, Jeremy <jerb...(a)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
From: Thomas 'PointedEars' Lahn on
RobG wrote:

> Jeremy wrote:
>> 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.

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
From: kangax on
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
From: Thomas 'PointedEars' Lahn on
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().


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