Easy Object Chaining Again

  • (2 Pages)
  • +
  • 1
  • 2

21 Replies - 1294 Views - Last Post: 05 March 2012 - 05:18 AM

#1 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Easy Object Chaining Again

Posted 26 February 2012 - 06:04 PM

In a previous post I got into some discussion of oop javascript with method chaining.

Various styles were used to implement chaining and my ultimate goal was to make the chains without using the new key word to form an object.

I have noticed something since that original post.
Here's that original post.
easy explanation of method chaining
Here are two code sets from that post.
Code set one:
<html> 
<body>
	<script type="text/javascript">
	var toys = function(s) { this.toy = s; return this; };
	var retoys = function(){ return "Cat: " + this.name + ", plays " + this.toy};

	function cat(name) {
		return {
			name : name, toy : 'none',
			plays : toys,			//toys = function
			toString : retoys, 		//retoys = function
		};
	}

	var spotted_cat = cat("spotted").plays("bites yarn");
	var striped_cat = cat("striped").plays("bites yarn");

	document.write("<p>" + spotted_cat + "</p>");
	document.write("<p>" + striped_cat + "</p>");
	</script>
</body>
</html>


Code set two:
<html> 
<body>
	<script type="text/javascript">
function cat(name) {
	function toys(s) { this.toy = s; return this; };
	function retoys() { return "Cat: " + this.name + ", plays " + this.toy};
	return {
		name : name, toy : 'none',
		plays : toys,
		toString : retoys,
	};
}

	var spotted_cat = cat("spotted").plays("bites yarn");
	var striped_cat = cat("striped").plays("bites yarn");

	document.write("<p>" + spotted_cat + "</p>");
	document.write("<p>" + striped_cat + "</p>");
	</script>
</body>
</html>



Now here is a new implementation using no 'this' operator, no toString method, and no extra function for converting and combining the string.
<!DOCTYPE html>
<head>
<title>js object</title>
</head>
<body>
<script type="text/javascript">
	
	var toyBox = function(player){
	    var toy = function(toyGet){
	        return "The " + player + " plays with the " + toyGet + "<br>";
	    }
	    return {
	        toy : toy
	    };
	}
	
	document.write(toyBox("Boy").toy("Ball"));
	document.write(toyBox("Girl").toy("Doll"));
	</script>
</body>
</html>



As you can see the toy function is referencing the 'player' parameter of toyBox. The chain comes out of the return of the literal and uses what parameters are provided.

I can't remember exactly what it was about the 'this' operator and what benefit it had for making method chains.

There is a discrepancy here between using the 'this' and just a plain return.
While using 'this' a toString is needed to convert the string for output, and the code needs extra object literal members to complete the operation.

I am wondering if there is some sort of benefit while using 'this' to produce method chaining versus benefits of just returning the function pointer in the literal.

The main benefit of either style is that the return is only applicable for the methods called in the chain. So it's nice to have for a quick extension directly in the object.

Is it easy vs. hard or is there a real reason for using 'this' to attach the properties to the function to accomplish method chaining?

This post has been edited by hiddenghost: 26 February 2012 - 06:23 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Easy Object Chaining Again

#2 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 26 February 2012 - 11:54 PM

View Posthiddenghost, on 27 February 2012 - 02:04 AM, said:

I can't remember exactly what it was about the 'this' operator and what benefit it had for making method chains.

you can reference the current object, even if it doesn't come from a literal.


View Posthiddenghost, on 27 February 2012 - 02:04 AM, said:

There is a discrepancy here between using the 'this' and just a plain return.
While using 'this' a toString is needed to convert the string for output, and the code needs extra object literal members to complete the operation.

the toString() method is native to all objects (unless you overwrite the prototype chain). an explicit toString() method is therefore only required if you want to have your output formatted differently to the default.


View Posthiddenghost, on 27 February 2012 - 02:04 AM, said:

I am wondering if there is some sort of benefit while using 'this' to produce method chaining versus benefits of just returning the function pointer in the literal.

memory. if you have the methods all in the constructor/factory method, each instance requires a full copy of the code, while prototyped methods are saved once (in the prototype chain) and then are available to all inheriting objects via reference.


View Posthiddenghost, on 27 February 2012 - 02:04 AM, said:

Is it easy vs. hard or is there a real reason for using 'this' to attach the properties to the function to accomplish method chaining?

method chaining itself doesn't make a statement about how you implement it. it is just a behavioural pattern that states that you can call (an appropriate method) directly from a previous method call. it does not even have to be the same object instance that needs to be called on.
Was This Post Helpful? 2
  • +
  • -

#3 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 27 February 2012 - 03:45 AM

Ok I have been experimenting with some times on writing out some strings from objects.
<!DOCTYPE html>
<head>
<title>js literal function pointer</title>
</head>
<body>
<script type="text/javascript">
	
	var toyBox = function(player){
	    var toy = function(toyGet){
	        return "The " + player + " plays with the " + toyGet + "<br>";
	    }
	    var game = function(gameGet){
	        return "The " + player + " plays " + gameGet + "<br>";
	    }
	    return  {
	        toy : toy,
	        game : game
	    };
	};
	for(i = 0; i < 5000; i = i + 1){
	document.write(toyBox("Boy").toy("Ball"));
	document.write(toyBox("Girl").toy("Doll"));
    document.write(toyBox("Boy").game("Mousetrap"));
	document.write(toyBox("Girl").game("Monopoly"));
	}
	</script>
</body>
</html>



<!DOCTYPE html>
<head>
<title>js prototype literal</title>
</head>
<body>
<script type="text/javascript">
	
	var toyBox = function(player){
	    return toyBox.prototype = {
	        toy : function(toyGet){
	            return "The " + player + " plays with the " + toyGet + "<br>";
	        },
	        game : function(gameGet){
	            return "The " + player + " plays " + gameGet + "<br>";
	        }
	    };
	};
	for(i = 0; i < 5000; i = i + 1){
	document.write(toyBox("Boy").toy("Ball"));
	document.write(toyBox("Girl").toy("Doll"));
    document.write(toyBox("Boy").game("Mousetrap"));
	document.write(toyBox("Girl").game("Monopoly"));
	}
	</script>
</body>
</html>



<!DOCTYPE html>
<head>
<title>js protype literal constructor</title>
</head>
<body>
<script type="text/javascript">
	
	var toyBox = function(player){
	    return toyBox.prototype = {
	        toy : this.toy = function(toyGet){
	            return "The " + player + " plays with the " + toyGet + "<br>";
	        },
	        game : this.game = function(gameGet){
	            return "The " + player + " plays " + gameGet + "<br>";
	        }    
	    };
	};
	for(i = 0; i < 5000; i = i + 1){
	document.write(toyBox("Boy").toy("Ball"));
	document.write(toyBox("Girl").toy("Doll"));
    document.write(toyBox("Boy").game("Mousetrap"));
	document.write(toyBox("Girl").game("Monopoly"));
	}
	</script>
</body>
</html>


Was This Post Helpful? 0
  • +
  • -

#4 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 27 February 2012 - 03:54 AM

the last two examples might quit with an error. even if they don't, their usage of prototype is wrong.
function MyConstructor(test)
{
    this.value = test;
}
MyConstructor.prototype.doSomething = function(test)
{
    this.value += test;
};
// or
MyConstructor.prototype = {
    doSomething: function (test) {
        this.value += test;
    }
};

be aware that the 1st variant only modifies the current prototype while the 2nd one replaces it. the difference might not be immediately visible, but you can get weird results when dealing with deeper inheritance.

This post has been edited by Dormilich: 27 February 2012 - 03:55 AM

Was This Post Helpful? 1
  • +
  • -

#5 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 27 February 2012 - 04:45 AM

What about this?
<!DOCTYPE html>
<head>
<title>js protype literal constructor</title>
</head>
<body>
<script type="text/javascript">
	
	var toyBox = function(player){
	    return this.prototype = {
	        toy : this.toy = function(toyGet){
	            return "The " + player + " plays with the " + toyGet + "<br>";
	        },
	        game : this.game = function(gameGet){
	            return "The " + player + " plays " + gameGet + "<br>";
	        }    
	    };

	};
	//for(i = 0; i < 5000; i = i + 1){
	document.write(toyBox("Boy").toy("Ball"));
	document.write(toyBox("Girl").toy("Doll"));
    document.write(toyBox("Boy").game("Mousetrap"));
	document.write(toyBox("Girl").game("Monopoly"));
	//}
	</script>
</body>
</html>


Was This Post Helpful? 0
  • +
  • -

#6 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 27 February 2012 - 04:55 AM

same as last time, the prototype has nothing to do inside the constructor.
Was This Post Helpful? 1
  • +
  • -

#7 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:28 AM

Ok. Now I understand why those were wrong.

The prototype is for setting new methods.
New methods are also set with the keyword this.

Both at the same time is redundant.

View PostDormilich, on 27 February 2012 - 04:54 AM, said:

the last two examples might quit with an error. even if they don't, their usage of prototype is wrong.
function MyConstructor(test)
{
    this.value = test;
}
MyConstructor.prototype.doSomething = function(test)
{
    this.value += test;
};
// or
MyConstructor.prototype = {
    doSomething: function (test) {
        this.value += test;
    }
};

be aware that the 1st variant only modifies the current prototype while the 2nd one replaces it. the difference might not be immediately visible, but you can get weird results when dealing with deeper inheritance.


What weird results?
Was This Post Helpful? 0
  • +
  • -

#8 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:51 AM

if you used nested inheritance (i.e. when you have a grandparent object) for example, you may encounter that inherited methods suddenly do not exist any more. even parent methods can be affected, if you extend before you define the prototype.

function extendObjBy(obj, parent)
{
    // some standard extend implementation here
}

function MyArray() 
{
    // …
}

// extending MyArray from Array
extendObjBy(MyArray, Array);

// defining new MyArray methods
// this will delete MyArray.prototype.prototype 
// (which points to Array.prototype)
MyArray.prototype = {
    // MyArray methods
};

This post has been edited by Dormilich: 04 March 2012 - 03:59 AM

Was This Post Helpful? 0
  • +
  • -

#9 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 04 March 2012 - 12:13 PM

Ok.

So in your original example.

MyConstructor.prototype.doSomething = function(test)
{
    this.value += test;
};
// or
MyConstructor.prototype = {
    doSomething: function (test) {
        this.value += test;
    }
};


The first .doSomething is getting set.
Even though the second .doSomething is inside the literal it is being used by the prototype and is becoming the next doSomething Method which is totally replacing the first .doSomething.

This post has been edited by hiddenghost: 04 March 2012 - 02:55 PM

Was This Post Helpful? 0
  • +
  • -

#10 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 04 March 2012 - 02:34 PM

the point is, in the first variant, the other properties of the prototype ain’t touched, while in the second, they’re overwritten with what’s in the literal (and its prototype, i.e. Object.prototype).
Was This Post Helpful? 0
  • +
  • -

#11 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 04 March 2012 - 02:55 PM

View PostDormilich, on 04 March 2012 - 03:34 PM, said:

the point is, in the first variant, the other properties of the prototype ain’t touched, while in the second, they’re overwritten with what’s in the literal (and its prototype, i.e. Object.prototype).


Ok.

If everything is defined in the literal does it just use the methods and properties there?
No overwriting?
Unless there is some other prototype before the literal?
Was This Post Helpful? 0
  • +
  • -

#12 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:06 PM

View PostDormilich, on 27 February 2012 - 12:54 AM, said:

memory. if you have the methods all in the constructor/factory method, each instance requires a full copy of the code, while prototyped methods are saved once (in the prototype chain) and then are available to all inheriting objects via reference.


Ah (%@P!

I just realised what you were trying to say.

If methods are defined with the keyword 'this'
They become a part of the object as a whole. They are copied with the new object every time.

If methods are defined with prototype
They are just one instance and that one instance is used with every call.

Using the literal is kind of like saying 'this' when a function pointer is assigned to the literal and the literal is returned. It's a copy.
Was This Post Helpful? 0
  • +
  • -

#13 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:19 PM

View Posthiddenghost, on 04 March 2012 - 11:06 PM, said:

Using the literal is kind of like saying 'this' when a function pointer is assigned to the literal and the literal is returned. It's a copy.

not really, the object literal is just a shortcut for new Object just like the array literal ([]) is just short for new Array. it has nothing to do with this at all.
Was This Post Helpful? 1
  • +
  • -

#14 hiddenghost  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 37
  • View blog
  • Posts: 599
  • Joined: 15-December 09

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:38 PM

View PostDormilich, on 04 March 2012 - 04:19 PM, said:

View Posthiddenghost, on 04 March 2012 - 11:06 PM, said:

Using the literal is kind of like saying 'this' when a function pointer is assigned to the literal and the literal is returned. It's a copy.

not really, the object literal is just a shortcut for new Object just like the array literal ([]) is just short for new Array. it has nothing to do with this at all.


So it's more like saying:
function Object(){
    insideObject = function(param){
        this.param;
    };
    this.internalObject = new insideObject();
}


Is like:
function Object(){
    internalObject = function(param){
        param;
    };
    return {
        internalObject : internalObject
    };
}


Was This Post Helpful? 0
  • +
  • -

#15 Dormilich  Icon User is offline

  • 痛覚残留
  • member icon

Reputation: 2894
  • View blog
  • Posts: 7,541
  • Joined: 08-June 10

Re: Easy Object Chaining Again

Posted 04 March 2012 - 03:42 PM

no.

1) "Object" is a reserved keyword (that’s the constructor every Javascript object inherits from)
2) the 2nd function does not qualify as object constructor (like in any other object-oriented language, constructors must not return anything)
Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2