Say i have a constructor, and some instance methods, like
function MyClass(name) {
this.name = name || '';
}
MyClass.prototype = {
constructor: MyClass,
isEmptyName: function() {
return this.name === '';
}
}
Now i can write
var myClass = new MyClass('Ben');
myClass.isEmptyName();
which would return false. Now if i make another method what would also return a Boolean
MyClass.prototype = {
constructor: MyClass,
isEmptyName: function() {
return this.name === '';
}
longerThan: function(len) {
return this.name.length > len;
}
}
i would like to chain these methods like this (somehow, thats my question :) )
myClass.isEmptyName().and.longerThan(2);
Just omit now the '.and.' part. I want the upper statement to finally return a value
false && true -> false
Or a more realistic sample:
myClass.notEmptyName().and.longerThan(4);
To summarize my problem i would say, i want my methods return a boolean value if they are called 'directly' myClass.notEmptyName() should return true, but work like i wrote in the samples, otherwise.
Other libraries do this somehow, but i can't guess how, npm's should is a good example:
user.should.have.property('pets').with.lengthOf(4);
user.pets.should.be.instanceof(Array).and.have.lengthOf(4);
Thanks
That's not possible. A method can't return either a boolean or be chainable depending on how it's used later on, because it doesn't know how it will be used later on.
You can chain methods that validate the object in different ways, but you need to get the result at the end if you want to use it in an expression, either by reading a property or calling a method:
function MyClass(name) {
this.name = name;
this.and = this;
}
MyClass.prototype = {
value: true,
isNotEmpty: function() {
this.value = this.value && this.name.length > 0; return this;
},
isLongerThan: function(len) {
this.value = this.value && this.name.length > len; return this;
},
evaluate: function() {
return this.value;
}
};
console.log(new MyClass('Adam').isLongerThan(2).evaluate());
console.log(new MyClass('Bob').isNotEmpty().and.isLongerThan(3).evaluate());
Demo: http://jsfiddle.net/Guffa/62e8dLwL/
Edit:
To allow evaluation more than once, you would reset the value in the evaluate method:
evaluate: function() {
var v = this.value;
this.value = true;
return v;
}
Sure, you can do that. We will define a new intermediate status object, called ChainResult, which remembers the underlying object, the current value, and a pending operation (a function to use to combine the next test). We give this object a valueOf method, so that when JS tries to evaluate it as a primitive, it "looks" like it has a value. To make this work, it turns out that ChainResult actually needs to be a function, and so we hang the necessary properties off the function.
function ChainResult(obj, val) {
function x() { }
x.obj = obj;
x.val = val;
x.op = null;
// the `valueOf` function spits out the current value when the object is evaluated
x.valueOf = function() { return this.val; };
// the test functions combine the results with the current value
// using the current operation as set by a preceding `and` or `or`
x.isEmptyName = function() {
x.val = x.op(x.val, x.obj._isEmptyName());
return this;
};
x.isLongerThan = function(len) {
x.val = x.op(x.val, x.obj._isLongerThan(len));
return this;
};
// we implement `and` and `or` via getters which set the operation
// on the ChainResult object, and return `this` so we can keep chaining
Object.defineProperties(x, {
and: {
get: function() { x.op = function(a,b) { return a && b; }; return x; }
},
or: {
get: function() { x.op = function(a,b) { return a || b; }; return x; }
}
});
return x;
}
The MyClass definition needs a bit of tweaking:
function MyClass(name) {
this.name = name || '';
}
MyClass.prototype = {
constructor: MyClass,
// we implement the testers as pseudo-private functions
_isEmptyName: function() { return this.name === ''; },
_isLongerThan: function(len) { return this.name.length > len; },
// when the public tester functions are invoked directly on the object
// (when they are the first link in the chain), we construct and return a
// ChainResult object with the initial value set correctly
isEmptyName: function() { return ChainResult(this, this._isEmptyName()); },
isLongerThan: function(len) { return ChainResult(this, this._isLongerThan(len)) }
};
Flow:
new MyClass('Bob') // create MyClass object
.isEmptyName() // create ChainResult object with value `false`
.or // remember `or` operation in ChainResult object
.isLongerThan(2) // update value of ChainResult object
; // JS tries to convert to scalar, calls valueOf
// true
This needs to be bullet-proofed and tightened up, but you get the idea.
i want my methods return a boolean value if they are called 'directly' myClass.notEmptyName() should return true
Your methods are always called directly on the instance, and would always need to return a primitive boolean value. By that, the context (myClass) is lost and you cannot have an and method (or property getter) on the result.
I would recommend you to have a look at functional programming, partial application and currying, which helps a lot with fluent interfaces like this. Given
function and(fn1, fn2) {
return function(val) {
return fn1(val) && fn2(val);
};
}
function or(fn1, fn2) {
return function(val) {
return fn1(val) || fn2(val);
};
}
function hasEmptyName: function(val) {
return val.name === '';
}
function hasNameLongerThan: function(len) {
return function(val) {
return val.name.length > len;
};
}
you could write
and(hasEmptyName, hasNameLongerThan(2))(myClass);
Making these functions methods of anything is complicated however. Maybe something like this:
function method(name) {
var args = Array.prototype.slice.call(arguments, 1);
return function(instance) {
return instance[name].apply(instance, args);
};
}
Function.prototype.and = function (fn2) {
var fn1 = this;
return function(val) {
return fn1(val) && fn2(val);
};
}
Function.prototype.or = function (fn2) {
var fn1 = this;
return function(val) {
return fn1(val) || fn2(val);
};
}
Object.defineProperty(Object.prototype, "test", function(pred) {
return pred(this);
});
Now you could write
myClass.test(method("notEmptyName").and(method("longerThan", 4)));
This is an answer (better call it to outcome) for my own question:
Finally i came out with another solution based on the responses in this thread (Thanks guys!) because the original problem can not be solved, since the javascript runtime can't find out wether to return a value, or return itself (the object) when chained. Explanation is messy, sorry :(
Check out my lib, where i have methods like:
check(value).isString() etc..
Originally i wanted to chain these like check(value).isString().and.not.empty() but this, in this way, can not be done. (Challenge me)
Finally i created tokens for chaining, so instead of
check(value).isString().and.not.empty()
I can write
check(value).isstring.and.not.empty.test()
Not nice, but still something.
check.js
For review, visit checkjs on my github repo.
Note: README is outdated.
If you use promises, you could write functions that return values and can be chained. Mind you, these are all asynchronous.
Find this JS plugin: Kris Owal's Q, or if you like to use a JS library, they usually contain deferred objects and promises.
Related
I have the following code :
function foo(){
this.bar = {
images: function() {
this.example = "string";
this.anotherFoo = true;
(...)
this.getBigPicturePositions = function(){};
return this;
},
search: function(){
this.thing = "string";
this.anotherBar = false;
(...)
this.newAjaxSearch = function(){};
return this;
}
}
}
And then, I have this declaration :
var foo = new foo();
foo.start({
bar: {
images: {
getBigPicturePositions: true
},
search: {
newAjaxSearch: true,
idontexist: true
}
}
});
How can I make a function like this who start the methods specified? I need this to start specific methods when i need to (if they exists of course). In my example, i need to get something like :
foo.bar.images().getBigPicturePositions();
foo.bar.search().newAjaxSearch();
Thank you for your help! I'm a newbie in javascript object.
UPDATE : The problem is solved with the solution presented by CrazyTrain but I have updated my code too. To view the result, please check this Fiddle
First, make the .start() method an inherited method for objects created from new foo()
foo.prototype.start = function(flags) {
// call our recursive invoker function
recursive_invoker(flags, this);
}
Then make a recursive function that iterates objects, and either recursively traverses nested objects when found, or invokes functions if a true value was given.
// holds the flags---v v---holds the methods
function recursive_invoker(flags, methods) {
// enumerate the properties of the `flags` object
for (var f in flags) {
if (typeof flags[f] === "object" && typeof methods[f] === "object") {
// objects were found, so make a recursive call with those objects
recursive_invoker(flags[f], methods[f]);
} else if (flags[f] === true && typeof methods[f] === "function") {
// `true` was found, so invoke the function on the "methods" object
methods[f]();
} else {
// Either we found `false`, or an object was not found, so do nothing.
// This `else` isn't really needed.
}
}
}
implement change prototype, so why not just directory change it with 'some class'.prototype..., It seems very useless or palaver
There are two aspects to implement. In a Class context and on Objects (Types/Natives).
Common benefits
Common between them is, they are API. Because it's API, MooTools can add ways that ensure that you don't (accidentally) overwrite prototype methods that are protected on various Native types. See this bit which forces protection for many native methods: https://github.com/mootools/mootools-core/blob/master/Source/Core/Core.js#L238-282
Also, implement is overloaded - which means you can pass on an object that implements more than one method at the same time, rather than break and have a new line for each prototype call.
Function Methods in Classes are wrapped.
These decorators are available:
Function.implement({
hide: function(){
this.$hidden = true;
return this;
},
protect: function(){
this.$protected = true;
return this;
}
});
This means you can do
Obj.implement({
foo: foo.hide(),
bar: bar.protect()
});
This allows you to have non-wrapped methods via .hide() to add properties that are not wrapped:
Number.prototype.$family = function(){
return isFinite(this) ? 'number' : 'null';
}.hide();
.protect() is used by Class, see below.
This does not mean you can't do Number.prototype.$family = somethingElse - you can.
Specifics to Class
When using implement on a class constructor, notice reference to $hidden and call to wrap():
var implement = function(key, value, retain){
if (Class.Mutators.hasOwnProperty(key)){
value = Class.Mutators[key].call(this, value);
if (value == null) return this;
}
if (typeOf(value) == 'function'){
if (value.$hidden) return this;
this.prototype[key] = (retain) ? value : wrap(this, key, value);
} else {
Object.merge(this.prototype, key, value);
}
return this;
};
This means when you pass a function, it will get wrapped automatically - wrapping enables you to have private methods via the .protect() decorator or special ones via .hide()
It also supports Class Mutators - you should check this but it's ability to define special keys that can modify the constructor, as opposed to just add to the prototype.
Once again, you can easily do:
ClassConstructor.prototype.foo = someFn;
And this will work.
// but:
ClassConstructor.prototype.foo = someFn.protect();
// however...
instanceOfClassconstructor.foo(); // works also.
see this:
// generic method.
var foo = function() {
console.log('hi');
};
var ClassConstructor = new Class({});
// implement the foo method as private.
ClassConstructor.implement({
foo: foo.protect()
});
var instance = new ClassConstructor();
// try to call it, will throw.
try {
instance.foo();
}
catch(e) {
console.warn(e);
}
// do it directly on the prototype
ClassConstructor.prototype.foo = foo.protect();
var instance2 = new ClassConstructor();
instance2.foo(); // works.
You can look at MooTools source or inspect a MooTools object in your console to see what it is doing under the hood when implement() is called.
In MooTools 1.4.5, it's doing this:
function (key, value){
if ($type(key) == 'object'){
for (var p in key) this.implement(p, key[p]);
return this;
}
var mutator = Class.Mutators[key];
if (mutator){
value = mutator.call(this, value);
if (value == null) return this;
}
var proto = this.prototype;
switch ($type(value)){
case 'function':
if (value._hidden) return this;
proto[key] = Class.wrap(this, key, value);
break;
case 'object':
var previous = proto[key];
if ($type(previous) == 'object') $mixin(previous, value);
else proto[key] = $unlink(value);
break;
case 'array':
proto[key] = $unlink(value);
break;
default: proto[key] = value;
}
return this;
}
As you can see, there is definitely some extra logic in there. For example, it seems that you can pass objects with corresponding property names for key and value to have it implement add multiple things to the object prototype in one call.
I would use implement() and avoid adding things directly to the prototype chain unless you are very sure you know what you're doing. That extra stuff is there for a reason, no doubt.
I'm working on a jQuery plugin that allows you to log any javascript class or object.
The idea is to override each function inside the object, or prototype of a function.
(function($)
{
"use strict";
$.log = function(object, logger)
{
if (!$.isFunction(logger))
{
logger = function(name, args)
{
console.log(name + "(" + $.makeArray(args).join(", ") + ")");
};
}
var s = $.isFunction(object) ? object.prototype : object;
for (name in s)
{
var fn = s[name];
if ($.isFunction(fn))
{
s[name] = (function(name, fn)
{
return function()
{
logger(name, arguments);
return fn.apply(this, arguments);
};
})(name, fn);
}
}
};
})(jQuery);
This seems to work for logging individual plugins. For example $.log($.ui.tabs); logs all the function calls inside the tabs prototype.
But when I want to log all of jQuery $.log($); it's giving me some reference error.
I can't figure out why I'm getting this error. I'm under the impression it has something to do with either this or the arguments being passed, but I'm not sure.
Edit: Now I think about It some more it might also be caused because the overridden function always returns.
I created a fiddle to demo the problem: http://jsfiddle.net/Sj6xN/4/
EDIT:
This is the code i ended up with, so far working perfectly:
(function($)
{
"use strict";
var Logger = function(options)
{
this.options = $.extend(this.defaults, options);
};
Logger.prototype = {
defaults:
{
inherited: false,
deep: false,
logWriter: function(name, args)
{
console.log("CALL: " + name + "(" + $.makeArray(args).join(", ") + ")");
}
},
augment: function(object)
{
var self = this;
// Make sure this object is not already augmented
if (object.__isAugmented__)
{
return;
}
// Set 'isAugmented' to prevent recursion
object.__isAugmented__ = true;
// Loop through the object
for (var name in object)
{
var originalFunction = object[name];
// If it's a function and the function is not inherited or 'inherited' is enabled augment it
if ($.isFunction(originalFunction) && (object.hasOwnProperty(name) || self.options.inherited))
{
// Wrap in self executing function so references to 'name' and 'orginalFunction' are maintained
object[name] = (function(name, originalFunction)
{
// If the function has a prototype and 'deep' is enabled augment that as well
if (self.options.deep && originalFunction.prototype)
{
self.augment(originalFunction.prototype);
}
var augmentedFunction = function()
{
// Execute log writer
self.options.logWriter(name, arguments);
// Call original function
return originalFunction.apply(this, arguments);
};
// Inherit prototype of original function
augmentedFunction.prototype = originalFunction.prototype;
// Return the augmented function
return augmentedFunction;
})(name, originalFunction);
}
// If it's a plain object and 'deep' is enabled augment that as well
else if (self.options.deep && $.isPlainObject(originalFunction))
{
self.augment(originalFunction);
}
}
}
};
$.log = function(object, options)
{
var logger = new Logger(options);
// If the object is a function use it's prototype, otherwise assume a plain object
object = $.isFunction(object) ? object.prototype : object;
// Augment
logger.augment(object);
};
})(jQuery);
Can be used like this:
$.log(<object or function> [,
{
inherited: <bool>,
deep: <bool>,
logWriter: <function(name, args)>
}]);
Well look closely to the error.
Uncaught ReferenceError: name is not defined
Means you haven't defined name and since you are in strict mode, you can't use a variable without defining it(normally if you do it, it'll be a global variable, but not in strict mode). So if you write a var name before it you won't get this error anymore.
Though there is another error for not having tab method. The other error says tabs is not a method of the object which is because when you wrap the function, you didn't inherit the prototype, so when the function is called with new, it doesn't have prototype functions(tabs is one of them).
Here's the fixed code : http://jsfiddle.net/Sj6xN/8/
Before I get yelled at for trying something so reckless, let me tell you that I wouldn't do this in real life and it's an academic question.
Suppose I'm writing a library and I want my object to be able to make up methods as they are needed.
For example if you wanted to call a .slice() method, and I didn't have one then the window.onerror handler would fire it for me
Anyway I played around with this here
window.onerror = function(e) {
var method = /'(.*)'$/.exec(e)[1];
console.log(method); // slice
return Array.prototype[method].call(this, arguments); // not even almost gonna work
};
var myLib = function(a, b, c) {
if (this == window) return new myLib(a, b, c);
this[1] = a; this[2] = b; this[3] = c;
return this;
};
var obj = myLib(1,2,3);
console.log(obj.slice(1));
Also (maybe I should start a new question) can I change my constructor to take an unspecified amount of args?
var myLib = function(a, b, c) {
if (this == window) return new myLib.apply(/* what goes here? */, arguments);
this[1] = a; this[2] = b; this[3] = c;
return this;
};
BTW I know I can load my objects with
['slice', 'push', '...'].forEach(function() { myLib.prototype[this] = [][this]; });
That's not what I'm looking for
As you were asking an academic question, I suppose browser compatibility is not an issue. If it's indeed not, I'd like to introduce harmony proxies for this. onerror is not a very good practice as it's just a event raised if somewhere an error occurs. It should, if ever, only be used as a last resort. (I know you said you don't use it anyway, but onerror is just not very developer-friendly.)
Basically, proxies enable you to intercept most of the fundamental operations in JavaScript - most notably getting any property which is useful here. In this case, you could intercept the process of getting .slice.
Note that proxies are "black holes" by default. They do not correspond to any object (e.g. setting a property on a proxy just calls the set trap (interceptor); the actual storing you have to do yourself). But there is a "forwarding handler" available that routes everything through to a normal object (or an instance of course), so that the proxy behaves as a normal object. By extending the handler (in this case, the get part), you can quite easily route Array.prototype methods through as follows.
So, whenever any property (with name name) is being fetched, the code path is as follows:
Try returning inst[name].
Otherwise, try returning a function which applies Array.prototype[name] on the instance with the given arguments to this function.
Otherwise, just return undefined.
If you want to play around with proxies, you can use a recent version of V8, for example in a nightly build of Chromium (make sure to run as chrome --js-flags="--harmony"). Again, proxies are not available for "normal" usage because they're relatively new, change a lot of the fundamental parts of JavaScript and are in fact not officially specified yet (still drafts).
This is a simple diagram of how it goes like (inst is actually the proxy which the instance has been wrapped into). Note that it only illustrates getting a property; all other operations are simply passed through by the proxy because of the unmodified forwarding handler.
The proxy code could be as follows:
function Test(a, b, c) {
this[0] = a;
this[1] = b;
this[2] = c;
this.length = 3; // needed for .slice to work
}
Test.prototype.foo = "bar";
Test = (function(old) { // replace function with another function
// that returns an interceptor proxy instead
// of the actual instance
return function() {
var bind = Function.prototype.bind,
slice = Array.prototype.slice,
args = slice.call(arguments),
// to pass all arguments along with a new call:
inst = new(bind.apply(old, [null].concat(args))),
// ^ is ignored because of `new`
// which forces `this`
handler = new Proxy.Handler(inst); // create a forwarding handler
// for the instance
handler.get = function(receiver, name) { // overwrite `get` handler
if(name in inst) { // just return a property on the instance
return inst[name];
}
if(name in Array.prototype) { // otherwise try returning a function
// that calls the appropriate method
// on the instance
return function() {
return Array.prototype[name].apply(inst, arguments);
};
}
};
return Proxy.create(handler, Test.prototype);
};
})(Test);
var test = new Test(123, 456, 789),
sliced = test.slice(1);
console.log(sliced); // [456, 789]
console.log("2" in test); // true
console.log("2" in sliced); // false
console.log(test instanceof Test); // true
// (due to second argument to Proxy.create)
console.log(test.foo); // "bar"
The forwarding handler is available at the official harmony wiki.
Proxy.Handler = function(target) {
this.target = target;
};
Proxy.Handler.prototype = {
// Object.getOwnPropertyDescriptor(proxy, name) -> pd | undefined
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(this.target, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
// Object.getPropertyDescriptor(proxy, name) -> pd | undefined
getPropertyDescriptor: function(name) {
var desc = Object.getPropertyDescriptor(this.target, name);
if (desc !== undefined) { desc.configurable = true; }
return desc;
},
// Object.getOwnPropertyNames(proxy) -> [ string ]
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(this.target);
},
// Object.getPropertyNames(proxy) -> [ string ]
getPropertyNames: function() {
return Object.getPropertyNames(this.target);
},
// Object.defineProperty(proxy, name, pd) -> undefined
defineProperty: function(name, desc) {
return Object.defineProperty(this.target, name, desc);
},
// delete proxy[name] -> boolean
delete: function(name) { return delete this.target[name]; },
// Object.{freeze|seal|preventExtensions}(proxy) -> proxy
fix: function() {
// As long as target is not frozen, the proxy won't allow itself to be fixed
if (!Object.isFrozen(this.target)) {
return undefined;
}
var props = {};
Object.getOwnPropertyNames(this.target).forEach(function(name) {
props[name] = Object.getOwnPropertyDescriptor(this.target, name);
}.bind(this));
return props;
},
// == derived traps ==
// name in proxy -> boolean
has: function(name) { return name in this.target; },
// ({}).hasOwnProperty.call(proxy, name) -> boolean
hasOwn: function(name) { return ({}).hasOwnProperty.call(this.target, name); },
// proxy[name] -> any
get: function(receiver, name) { return this.target[name]; },
// proxy[name] = value
set: function(receiver, name, value) {
this.target[name] = value;
return true;
},
// for (var name in proxy) { ... }
enumerate: function() {
var result = [];
for (var name in this.target) { result.push(name); };
return result;
},
// Object.keys(proxy) -> [ string ]
keys: function() { return Object.keys(this.target); }
};
I have this code:
var myWidget = $('#myWidget');
and calls like this elsewhere:
myWidget.hide();
myWidget.slideToggle();
These work of course because jQuery adds these methods.
Now, let's say I'm doing some refactoring to make myWidget a proper object with its own custom methods and state:
var myWidget = (function() {
// private stuff
var actualJQueryObject = $('#myWidget');
return {
publicMethod: function() {...},
// MAGIC!
}
})()
but I want to have all the calls that expect a jQuery object, which are all around my code, to still work even though myWidget is no longer a jQuery object, because myWidget knows how to delegate these calls to actualJQueryObject.
Is this possible?
You could also extend your jQuery object, with another object that has your custom methods:
var myWidget = function() {
// private stuff
var actualJQueryObject = $('#myWidget');
var extensionMethods = {
publicMethod: function() { alert('public method!'); }
}
return $.extend(actualJQueryObject, extensionMethods);
}();
Just be careful with the name of your extension methods, to not clash with any other jQuery defined function.
You can try the above snippet here.
One option is using the original jquery object as a prototype.
function wrap(jqObject) {
function MyNewType() {
this.changeFontSize = function(a) {
this.css({fontSize : this.size});
};
}
MyNewType.prototype = jqObject;
return new MyNewType;
}
var obj = wrap($('#someitem'));
obj.size = 50; // obj.size
obj.changeFontSize(); // obj.changeFontSize
obj.hide(); // $.hide
obj.fadeIn("slow"); // $.fadeIn
I've written a plugin that might help you. It's basically a plugin for writing plugins. This dev group post explains it and has some code samples:
http://groups.google.com/group/jquery-dev/browse_thread/thread/664cb89b43ccb92c/72cf730045d4333a?hl=en&q=structure+plugin+authoring#72cf730045d4333a
And the source is here:
http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js
EDIT:
I created a function that has similar functionality to that plugin:
jQuerify = function(fn) {
function plugin() {
var instantiate = false;
// check to see if it has any prototyped methods (we only need one iteration to do this)
for (var i in construct.prototype) {
instantiate = true;
break;
}
// if there are prototyped methods, return an instance (since an instance's return value won't vary)
// otherwise just call it using apply so the return value can vary
return instantiate
? new construct(this, arguments)
: construct(this, arguments);
}
function construct(parent, args) {
// 'this' will not mimic jQuery unless given the length property
this.length = 0;
this.selector = parent.selector;
this.context = parent.context;
// mimic 'this' in jQuery, but for the plugin namespace
Array.prototype.push.apply(this, $.makeArray(parent));
// return the constructors return value
// should be 'this' if you want to chain the new namespace
return fn.apply(this, arguments);
}
// copy all static properties and methods
for (var i in fn) {
plugin[i] = fn[i];
}
// allow .fn and copy all instance properties and methods; the last part is for IE
plugin.fn = construct.prototype = plugin.prototype = fn.prototype;
return plugin;
}
This allows you to add custom objects to jQuery as a plugin while using 'this' to refer to the selected objects and also allows you to have an unlimited depth to your namespace:
function test1() {
return this;
}
test1.prototype.getHtml1 = function() {
return $(this).html();
}
function test2() {
return this;
}
test2.prototype.getHtml2 = function() {
return $(this).html();
}
function test3() {
return this;
}
test3.prototype.getHtml3 = function() {
return $(this).html();
}
jQuery.fn.test1 = jQuerify(test1);
jQuery.fn.test1.fn.test2 = jQuerify(test2);
jQuery.fn.test1.fn.test2.fn.test3 = jQuerify(test3);
jQuery(function($) {
alert($('body').test1().getHtml1());
alert($('body').test1().test2().getHtml2());
alert($('body').test1().test2().test3().getHtml3());
});