Blog Entry - 20th February 2010 - Programming - JavaScript

Emulating hasOwnProperty


Introduction

Following some interesting and helpful comments from Asen, I have decided, for a little fun, to examine in a bit more detail (of little or no practical use) the possible ways to emulate hasOwnProperty.

hasOwnProperty is only relevant to JavaScript objects that use prototypical inheritance, inheriting ultimately from Object, and its purpose is to decide whether a given named property is:-

(a) A direct property of the object itself. I leave unanswered what I mean by direct.

(b) A property of a prototype which is inherited (by look-up) through the object's prototype-chain.

I decided some time ago to try to emulate hasOwnProperty, mainly because I was finding bugs in Opera's implementation; although I can't seem to reproduce them now.

As hasOwnProperty is now well implemented, the need for any emulation of it is pretty much non-existent, but the exercise at least improved my understanding of some elements of the ECMAScript specification around prototype and constructor etc.

Ultimately my emulation turned out to be no different to that which is (I think) in the YUI library, containing one signficant compromise, which I will mention now : if your object has a property which contains a primitive value (e.g. 1) and a prototype in the chain also contains an identical property with a primitive value of 1, then there is no (simple) way (using my preferred method) to tell them apart, and the code therefore assumes that your object does NOT have that property (i.e. the code defers to the prototype) and returns false.

Prototype and Functional Inheritance

Assuming that you need inheritance at all, there options as to how you implement it.

I am aware that best practice may not always be to use prototype based inheritance, particularly for the security consious, notwithstanding that it offers benefits in terms of memory (no duplication of functions).

Some prefer the functional inheritance pattern (an alternative suggested by Douglas Crockford); provided you want objects which are not going to be too numerous, will not have too many functions, and require high levels of security.

I suspect that having both ways in your armoury (prototype and functional) and applying them judiciously, is the way forward.

My emulation of hasOwnProperty is only relevant to prototype based inheritance. In functional inheritance, each instance has its own unique copies of any "inherited" methods and other properties, so hasOwnProperty would be pretty much true for everything.

Functional Method

A simple example of the functional method is set out below. You can find some interesting discussion at Here and Here.

The key points of the functional method are:-

(a) You only have one object and all properties and methods are direct properties and methods of that object.

(b) Inheritance is not by prototoype. It is simply by adding to the object directly the inherited properties and methods.

(c) It is more memory intensive, as you create separate copies of all properties and methods for each instance of the object.

(d) There are some advantages with (c), particularly as you avoid use of this (by using an object reference as a closure), and it gives you strong privacy options through closures. It also makes calling "super" methods very easy.

(e) You have to implement your own type detection as instanceof does not work (without some mucking around).

function GrandParent()
{
	var self = {};

	function toString()
	{
		return "GrandParent";
	}

	self.toString = toString;

	return self;
}


function Parent()
{
	var self = new GrandParent();

	function toString()
	{
		return super_toString() + ">" + "Parent";
	}

	var super_toString = self.toString;
	self.toString = toString;
	return self;
}

function Child()
{
	var self = new Parent();

	function toString()
	{
		return super_toString() + ">" + "Child";
	}

	var super_toString = self.toString;
	self.toString = toString;

	return self;
}

function Son(self)
{
	self = self || new Child();

	function toString()
	{
		return super_toString() + ">" + "Son";
	}

	var super_toString = self.toString;
	self.toString = toString;
	return self;
}

function test()
{
	var child = new Child();
	alert(child.toString());

	Son(child);
	alert(child.toString());	
}

test();

editplay

The Son part of the example above demonstrates the decoration version of this, which looks at it the other way round. Instead of inheritance, you view it as taking an object and then specialising it with extra methods.

Either way, the functional method does not really need hasOwnProperty.

You could have a slight derivation of the functional method if you wanted, whereby you create a one-off prototype for your instance and add all standard properties and methods to that, so that you separated truely instance specific (on the instance object) from inherited (on a single prototype).

function GrandParent()
{
	function f(){};
	var proto = f.prototype = {};

	var self = new f();
	self.proto = proto;

	function toString()
	{
		return "GrandParent";
	}

	self.proto.toString = toString;

	return self;
}


function Parent()
{
	var self = new GrandParent();
	var proto = self.proto;

	function toString()
	{
		return super_toString() + ">" + "Parent";
	}

	var super_toString = proto.toString;
	proto.toString = toString;
	return self;
}

function Child()
{
	var self = new Parent();
	var proto = self.proto;

	function toString()
	{
		return super_toString() + ">" + "Child";
	}

	var super_toString = proto.toString;
	proto.toString = toString;

	return self;
}

function test()
{
	var child = new Child();
	alert(child.toString());
}

test();

editplay

Classic Prototype Inheritance

The classic protoypical inheritance method is well understood.

function GrandParent() {}

GrandParent.prototype.toString = function()
{
	return "GrandParent";
};


function Parent() {}

Parent.prototype = new GrandParent();

Parent.prototype.toString = function()
{
	return GrandParent.prototype.toString.apply(this) + ">" + "Parent";
};

function Child(){}

Child.prototype = new Parent();

Child.prototype.toString = function()
{
	return Parent.prototype.toString.apply(this) + ">" + "Child";
};

function test()
{
	var child = new Child();
	alert(child.toString());
}

editplay

The main advantage of using the prototoype chain is memory saving. The functions are only created once, rather than cloned for each instance of the object.

It is typically supported with an Extend function, to make up for some limitations in the ECMAScript specification; such as to provide additional properties to enable walking up and down the prototype chain, to facilitate use of instanceof, and to provide a clear separation between constructor functions and prototypes by using a dummy function as a prototype (can't remember why this matters much).

Normally you extend by saying Child.prototype = new Parent(). In fact, a more popular variant on the Extend is to ignore the actual constructor functions of your parent classes and say Child.prototype = Parent.prototype so that Parent is a mere placeholder and serves no function. To my mind, this is only relevant if you do not want your parent constructor functions to actually do anything useful, such as:-

(a) Carrying out some pre-processing.

(b) Creating some dynamic properties to be inherited through the prototype chain.

(c) Creating some new instance properies on your actual instance.

In my implementation below, I give you the choice of both.

The main flaw (other than perhaps security and use of this) in the prototypical inheritance method is it is very verbose when it comes to calling "super" methods. It is in fact rare that you need to call super methods, and I have already addressed this issue extensively in a previous blog entry, which Asen commented usefully on.

Here is my typical implementation. I like to wrap my class implementations in some form of closure, to provide for private class variables.

var extendProtoOnly = true;

function Extend (
	constructor /*: Function*/,
	superConstructor /*: Function*/,
	extendProtoOnly /*: Boolean*/
) /*: Object*/
{
	var superPrototype /*: Object*/ = extendProtoOnly ? superConstructor.prototype : new superConstructor();
	
	var f /*: Function*/ = function(){};
	f.prototype = superPrototype;
	var proto /*: Object*/ = new f();

	constructor.prototype = proto;

	proto.prototype = proto;  // note this is a circular reference
	proto.constructor = constructor;
	proto.superPrototype = superPrototype;
	proto.superConstructor = superConstructor;

	return proto;
}

var GrandParent = (function(){

	function GrandParent() 
	{

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new GrandParent()";
		};
	}

	var proto = Extend(GrandParent, Object, extendProtoOnly);

	proto.toString = function()
	{
		return (proto.superPrototype === Object.prototype ? "Object.prototype" : "Object.prototype>new Object()") + ">" +"GrandParent.prototype";
	};

	return GrandParent;
})();

var Parent = (function(){

	function Parent() 
	{

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Parent()";
		};

	}

	var proto = Extend(Parent, GrandParent, extendProtoOnly);

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Parent.prototype";
	};

	return Parent;
})();

var Child = (function(){

	function Child()
	{

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Child()";
		};

	}

	var proto = Extend(Child, Parent, extendProtoOnly);

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Child.prototype";
	};

	return Child;
})();

function test()
{
	var child = new Child();
	alert(child.toString());
}

editplay

This will give you a prototype chain that looks like this:-


|-new Child()  
|
|-Child.prototype = new f() 
|
|-f.prototype = new Parent()
|
|-Parent.prototype = new f()   
|
|-f.prototype = new GrandParent()
|
|-GrandParent.prototype = new f()
|
|-f.prototype = new Object()  // never used
|
|-Object.prototype

Or if you extend using extendProtoOnly you get:-


|-new Child() 
|
|-Child.prototype = new f()
|
|-Parent.prototype = new f()
|
|-GrandParent.prototype = new f()
|
|-Object.prototype

I will use this code as the basis for my further investigations in this blog entry.

Working up the prototype chain

Before we look at the implementation of hasOwnProperty we may as well look at walking the prototype chain, and this may become relevant to some implementations (although probably not much).

At the end of this section is some example code that demonstrates each method.

Firefox's __proto__ property

If you are using Firefox then it provides a hidden property on all objects called proto which lets you easily walk up the prototype chain. This property is non-standard, and is supported by most, but not all, other browsers (notably not IE).

In effect, each object has its own hidden property, which points to the next prototype up in the prototype chain.

Note that Object.prototype.__proto__ is null.

Express __super !property

If we are desperate, we could create our own express "__proto__" property on each instance of an object we create. Probably best to call it something else, such as "__super__" so as not to conflict.

Note that Object.prototype.__super__ will be undefined, rather than null.

E.g. a simple version...

function Child()
{

}

var c = new Child();
c.__super__ = Child.prototype;

or make it a little more automatic...

function Child()
{
	this.__super__ = Child.prototype;			
}

var c = new Child();

or get carried away with a special New function...

function New(constructor)
{
	var f = function(){};
	f.prototype = constructor.prototype;
	f.prototype.constructor = constructor;
	var args = Array.prototoype.slice(arguments, 1);
	var instance = new f();
	constructor.apply(instance, args);
	instance.__super__ = constructor.prototype;
	return instance;
}

Either way, we need to be consistent, in order to stitch together our chain.

The obvious problem with all this (apart from memory consumption) is that you now have an enumerable property on each instance, which you are going to have to watch out for in your name in Child type operations.

Using Extend

If I use my Extend function (which avoids creating properties on each instance of the Child class), then the way to walk up the prototype chain is a little bit messy, because of the circular references involved with proto.prototoype = proto.

The way to walk up the prototype chain is to follow the prototype and superPrototype properties alternating from one to the other (because prototype is a circular reference), and looking out for Object.prototype as a special case.

Demonstration

Given the above, lets test it out:-

var extendProtoOnly = false;

function New(constructor)
{
	var f = function(){};
	f.prototype = constructor.prototype;
	var args = Array.prototype.slice.call(arguments, 1);
	var instance = new f();
	constructor.apply(instance, args);
	instance.__super__ = constructor.prototype;
	return instance;
}


function Extend (
	constructor /*: Function*/,
	superConstructor /*: Function*/,
	extendProtoOnly /*: Boolean*/
) /*: Object*/
{
	var superPrototype /*: Object*/ = extendProtoOnly ? superConstructor.prototype : New(superConstructor);
	
	var f /*: Function*/ = function(){};
	f.prototype = superPrototype;
	var proto /*: Object*/ = New(f);

	constructor.prototype = proto;

	proto.prototype = proto;  // note this is a circular reference
	proto.constructor = constructor;
	proto.superPrototype = superPrototype;
	proto.superConstructor = superConstructor;

	if (!extendProtoOnly && superConstructor === Object.prototype.constructor)
	{
		superPrototype.prototype = superPrototype;
		superPrototype.constructor = superConstructor;
		superPrototype.superPrototype = Object.prototype;
		superPrototype.superConstructor = null;
	}

	return proto;
}

Object.prototype.draw = function()
{
	alert("Object.prototype.draw()");
}


var GrandParent = (function(){

	function GrandParent() 
	{
		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new GrandParent()";
		};

		this.draw = function()
		{
			alert("GrandParent.draw()");
		}
	}

	var proto = Extend(GrandParent, Object, extendProtoOnly);

	proto.primitive_number = 1;
	proto.primitive_string = "1";

	proto.toString = function()
	{
		return (proto.superPrototype === Object.prototype ? "Object.prototype" : "Object.prototype>new Object()") + ">" +"GrandParent.prototype";
	};

	proto.draw = function()
	{
		alert("GrandParent.prototype.draw()");
	};

	proto.clear = function()
	{
		alert("GrandParent.prototype.clear()");
	};

	return GrandParent;
})();

var Parent = (function(){

	function Parent() 
	{

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Parent()";
		};

		this.draw = function()
		{
			alert("Parent.draw()");
		}


	}

	var proto = Extend(Parent, GrandParent, extendProtoOnly);

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Parent.prototype";
	};

	proto.draw = function()
	{
		alert("Parent.prototype.draw()");
	};

	return Parent;
})();

var Child = (function(){

	function Child(testArg)
	{
		this.primitive_number = 1;
		this.testArg = testArg;

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Child('" + this.testArg + "')";
		};

		this.draw = function()
		{
			alert("Child.draw()");
		}

	}

	var proto = Extend(Child, Parent, extendProtoOnly);

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Child.prototype";
	};

	proto.draw = function()
	{
		alert("Child.prototype.draw()");
	};

	return Child;
})();

function test()
{
	var child = New(Child, 2);
	alert("Child.toString: " + child.toString());

/*
	alert("child.hasOwnProperty('primitive_number') = " + child.hasOwnProperty('primitive_number') + " (should be true).");
	alert("child.hasOwnProperty('primitive_string') = " + child.hasOwnProperty('primitive_string') + " (should be false).");
	alert("child.hasOwnProperty('draw') = " + child.hasOwnProperty('draw') + " (should be true).");
	alert("child.hasOwnProperty('clear') = " + child.hasOwnProperty('clear') + " (should be false).");

	alert("child instanceof Child = " + (child instanceof Child) + " (should be true).");
	alert("child instanceof GrandParent = " + (child instanceof GrandParent) + " (should be true).");
*/
	alert("Using __proto__ ");

	var s = "";

	while(child)
	{

		s += child.draw.toString().replace(/\r|\n|\t/g,"") + "\r\n";
		s += /([A-Za-z_]+)\s*\(/.exec(child.constructor)[1] + "\r\n";
		s += "---------------------\r\n";
		child = child.__proto__;
	}


	alert(s);

	var child = New(Child, 2);

	alert("Using __super__ ");

	var s = "";

	while(child)
	{
		s += child.draw.toString().replace(/\r|\n|\t/g," ") + "\r\n";
		s += /([A-Za-z_]+)\s*\(/.exec(child.constructor)[1] + "\r\n";
		s += "---------------------\r\n";

		child = child.__super__;
	}

	alert(s);


	alert("Using Extend properties");

	var child = New(Child, 2);


	var s = "";

	while(child)
	{
		s += child.draw.toString().replace(/\r|\n|\t/g," ") + "\r\n";
		s += /([A-Za-z_]+)\s*\(/.exec(child.constructor)[1] + "\r\n";
		s += "---------------------\r\n";

		child = (child.prototype) ? (child.prototype === child) ? child.superPrototype : child.prototype : null;

//does not actualll go to object.prototype
	}

	alert(s);


}

test();

editplay

HasOwnProperty - Version 1 - Preferred

Finally, we get to the emulation of HasOwnProperty.

function HasOwnProperty (
	targetObject /*: Any*/, 
	propertyName /*: String*/
) /*: Boolean*/
{
	var t /*: String*/ = typeof targetObject;

	if (t === "undefined" || t === "unknown" || targetObject === null)
	{
		return false;  // perhaps throw an error
	}

	t = typeof targetObject[propertyName];

	if (t === "unknown")
	{
		return false;  // perhaps throw an error
	}

	if (typeof targetObject.hasOwnProperty == "function" /* && IS_NOT_OPERA */)
	{
		return targetObject.hasOwnProperty(propertyName);
	}

	if (!(propertyName in targetObject))
	{
		return false;
	}

	/* This depends on what you you use for extending your functions */
	var proto /*: Object*/ = targetObject.__proto__ || targetObject.__super__ || targetObject.prototype || (targetObject.constructor && targetObject.constructor.prototype) || null;

	if (!proto)
	{
		return true;  // compromise
	}

	/* ``Extend`` creates a circular reference */
	if (proto === targetObject)
	{
		proto = proto.__proto__ || proto.__super__ || proto.superPrototype || null;

		if (!proto)
		{
			return true;  // compromise
		}
	}

	if (!(propertyName in proto))
	{
		return true;
	}

	if (targetObject[propertyName] !== proto[propertyName])
	{
		return true;
	} 

	return false;  // compromise
}

In this emulation (which is the same, I think, as that used by YUI, the test is simply as to whether the property on the target object is ``== a property of the same name from the prototoype or up. If they are === then there is an ambiguity, and the function errs on the side of caution and returns false. The same goes for a few other points noted below.

How can we get round the compromise at the end?

HasOwnProperty - Version 2 - Delete Proto Method

If your browser supports __proto__ and editing it, then you could delete the prototype temporarily:-

....

	if (targetObject[propertyName] !== proto[propertyName])
	{
		return true;
	} 

	if (targetObject.__proto__)
	{
		var proto = targetObject.__proto__;
		targetObject.__proto__ = null;
		var result = propertyName in targetObject;
		targetObject.__proto__ = proto;
		return result;
	}

	//return false;  // compromise

I will not investigate this further, as it is not cross browser.

HasOwnProperty - Version 3 - Examine the prototype chain top down

The third option to get round the compromise is to examine the prototype chain top down, and to delete each matching ('===') property, and then re-attach it afterwards. Madness, I know.

If you ever use this, I am hoping that you will only have to do this after all the other tests have failed to resolve any doubt.

The following example uses my __super__ property, just for testing purposes.

...

	if (targetObject[propertyName] !== proto[propertyName])
	{
		return true;
	} 

	var chain = [];
	var obj = proto;

	while(obj)
	{
		chain.unshift(obj);
		obj = obj.__super__;
	}

	var undef; // undefined
	var link /*: Object*/;
	var overflow /*: int*/ = 100;
	var result /*: Boolean*/;
	var deleted /*: Array.<Object.<Any>>*/ = [];
	var deleteResult /*: Boolean*/ = false;

	for (var i = 0; i < chain.length; i++)
	{
		proto = chain[i];

		link = {proto: proto, val : undef};

		if (propertyName in proto && proto[propertyName] === targetObject[propertyName])
		{
			link.val = proto[propertyName];

			deleteResult = delete proto[propertyName];

			if (deleteResult == false || proto[propertyName] === link.val)
			{
				return false;  // compromise
			}

			deleted[deleted.length] = link;
		}
	}

	result = propertyName in targetObject;

	for (var i /*: int*/ = 0; i < deleted.length; i++)
	{
		deleted[i].proto[propertyName] = deleted[i].val;
	}
	
	return result;	
}

I does actually work!

Anyway, try for yourself. I am now bored!


var extendProtoOnly = false;

function New(constructor)
{
	var f = function(){};
	f.prototype = constructor.prototype;
	var args = Array.prototype.slice.call(arguments, 1);
	var instance = new f();
	constructor.apply(instance, args);
	instance.__super__ = constructor.prototype;
	return instance;
}


function Extend (
	constructor /*: Function*/,
	superConstructor /*: Function*/,
	extendProtoOnly /*: Boolean*/
) /*: Object*/
{
	var superPrototype /*: Object*/ = extendProtoOnly ? superConstructor.prototype : New(superConstructor);
	
	var f /*: Function*/ = function(){};
	f.prototype = superPrototype;
	var proto /*: Object*/ = New(f);

	constructor.prototype = proto;

	proto.prototype = proto;  // note this is a circular reference
	proto.constructor = constructor;
	proto.superPrototype = superPrototype;
	proto.superConstructor = superConstructor;

	if (!extendProtoOnly && superConstructor === Object.prototype.constructor)
	{
		superPrototype.prototype = superPrototype;
		superPrototype.constructor = superConstructor;
		superPrototype.superPrototype = Object.prototype;
		superPrototype.superConstructor = null;
	}

	return proto;
}

Object.prototype.draw = function()
{
	alert("Object.prototype.draw()");
}


var GrandParent = (function(){

	function GrandParent() 
	{
		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new GrandParent()";
		};

		this.draw = function()
		{
			alert("GrandParent.draw()");
		}
	}

	var proto = Extend(GrandParent, Object, extendProtoOnly);

	proto.primitive_number = 1;
	proto.primitive_number2 = 2;
	proto.primitive_string = "1";

	proto.toString = function()
	{
		return (proto.superPrototype === Object.prototype ? "Object.prototype" : "Object.prototype>new Object()") + ">" +"GrandParent.prototype";
	};

	proto.draw = function()
	{
		alert("GrandParent.prototype.draw()");
	};

	proto.clear = function()
	{
		alert("GrandParent.prototype.clear()");
	};

	return GrandParent;
})();

var Parent = (function(){

	function Parent() 
	{

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Parent()";
		};

		this.draw = function()
		{
			alert("Parent.draw()");
		}


	}

	var proto = Extend(Parent, GrandParent, extendProtoOnly);

	proto.primitive_number2 = 2;

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Parent.prototype";
	};

	proto.draw = function()
	{
		alert("Parent.prototype.draw()");
	};

	return Parent;
})();

var Child = (function(){

	function Child(testArg)
	{
		this.primitive_number = 1;
		this.primitive_number2 = 2;
		this.testArg = testArg;

		this.toString = function()
		{
			return proto.toString.apply(this) + ">" + "new Child('" + this.testArg + "')";
		};

		this.draw = function()
		{
			alert("Child.draw()");
		}

	}

	var proto = Extend(Child, Parent, extendProtoOnly);

	proto.toString = function()
	{
		return proto.superPrototype.toString.apply(this) + ">" + "Child.prototype";
	};

	proto.draw = function()
	{
		alert("Child.prototype.draw()");
	};

	return Child;
})();


function HasOwnPropertyMadVersion (
	targetObject /*: Any*/, 
	propertyName /*: String*/
) /*: Boolean*/
{
	var t /*: String*/ = typeof targetObject;

	if (t === "undefined" || t === "unknown" || targetObject === null)
	{
		return false;  // perhaps throw an error
	}

	t = typeof targetObject[propertyName];

	if (t === "unknown")
	{
		return false;  // perhaps throw an error
	}

	if (typeof targetObject.hasOwnProperty == "function" /* && IS_NOT_OPERA */)
	{
		// DISABLED
		//return targetObject.hasOwnProperty(propertyName);
	}

	if (!(propertyName in targetObject))
	{
		return false;
	}

	/* This depends on what you you use for extending your functions */
	var proto /*: Object*/ = targetObject.__proto__ || targetObject.__super__ || targetObject.prototype || (targetObject.constructor && targetObject.constructor.prototype) || null;

	if (!proto)
	{
		return true;  // compromise
	}

	/* ``Extend`` creates a circular reference */
	if (proto === targetObject)
	{
		proto = proto.__proto__ || proto.__super__ || proto.superPrototype || null;

		if (!proto)
		{
			return true;  // compromise
		}
	}


	if (!(propertyName in proto))
	{
		return true;
	}

	if (targetObject[propertyName] !== proto[propertyName])
	{
		return true;
	} 

	var chain = [];
	var obj = proto;

	while(obj)
	{
		chain.unshift(obj);
		obj = obj.__super__;
	}

	var undef; // undefined
	var link /*: Object*/;
	var overflow /*: int*/ = 100;
	var result /*: Boolean*/;
	var deleted /*: Array.<Object.<Any>>*/ = [];
	var deleteResult /*: Boolean*/ = false;

	for (var i = 0; i < chain.length; i++)
	{
		proto = chain[i];

		link = {proto: proto, val : undef};

		if (propertyName in proto && proto[propertyName] === targetObject[propertyName])
		{
			link.val = proto[propertyName];

			deleteResult = delete proto[propertyName];

			if (deleteResult == false || proto[propertyName] === link.val)
			{
				return false;  // compromise for Object.prototype
			}

			deleted[deleted.length] = link;
		}
	}

	result = propertyName in targetObject;


	for (var i /*: int*/ = 0; i < deleted.length; i++)
	{
		deleted[i].proto[propertyName] = deleted[i].val;
	}


	// DEBUG
	var s = "For : " + propertyName + "\r\n" + "=============\r\n";
	chain.push(targetObject);
	for (var i = 0; i < chain.length; i++)
	{
		link = chain[i];
		s += "Constructor : " + /([A-Za-z_]+)\s*\(/.exec(link.constructor)[1] + "\r\n";
		s += "hasOwnProperty('" + propertyName + "') = " + link.hasOwnProperty(propertyName) + "\r\n";

		if (link.hasOwnProperty(propertyName))
		{
			s += propertyName + " = " + link[propertyName] + "\r\n";
		}

		s += "---------------------\r\n";
	}
	alert(s);

	
	return result;	


	
}

function test()
{
	var child = New(Child, 2);
	alert("Child.toString: " + child.toString());

	alert("child.hasOwnProperty('primitive_number') = " + child.hasOwnProperty('primitive_number') + " (should be true).");
	alert("HasOwnProperty(child, 'primitive_number') = " + HasOwnPropertyMadVersion(child, 'primitive_number') + " (should be true).");
	alert("HasOwnProperty(child, 'primitive_number2') = " + HasOwnPropertyMadVersion(child, 'primitive_number2') + " (should be true).");
	alert("HasOwnProperty(child, 'primitive_string') = " + HasOwnPropertyMadVersion(child, 'primitive_string') + " (should be false).");
	alert("HasOwnProperty(child, 'toString') = " + HasOwnPropertyMadVersion(child, 'toString') + " (should be true).");
	alert("HasOwnProperty(child, 'hasOwnProperty') = " + HasOwnPropertyMadVersion(child, 'hasOwnProperty') + " (should be false).")
}

test();

editplay


Comment(s)


Sorry, comments have been suspended. Too much offensive comment spam is causing the site to be blocked by firewalls (which ironically therefore defeats the point of posting spam in the first place!). I don't get that many comments anyway, so I am going to look at a better way of managing the comment spam before reinstating the comments.


Leave a comment ...


{{PREVIEW}} Comments stopped temporarily due to attack from comment spammers.