jquery reminder

Things you better know before you write JS code.

unorganized code is hell


                     It mess everthing up.

                    Bad pattern Including :
  • Always use global objects
  • God object
  • One operation in multiple event
  • Variable name conflict
  • Scope issue
  • null issue

Always use global objects


            base.js
            window.User = $("#table");
            
            page.js
            $("#user").click(function(){
                    User.append("<tr><td>new user</td></tr>");
            });

            Bad Practice!

God object

GOD OBJECT
var Comment = {  
	usercomment: {
		edit: function(str){
			$("#item"+this.current_id).text(str);
			Comment.usercomment.update();
		},
		init:function(){
			$("#btn").click(function(){ 
				Comment.tablecomment.show();
			});
		},
		list:function(){ /* ....... */}
	}, 
	tablecomment: {
		show:function(){/* ....... */} 
	}, 
	/* ...... */
};
Comment.usercoment.init();

one operation in multiple event.

$("#btn").click(function(){
	var $target = $("#target");
	$target.find(".view").hide();
	$target.find(".edit").show();

});
$("#target").find(".edit .submit").click(function(){
	//validation
	//submit
});
$("#target").find(".edit .cancel").click(function(){
	$target.find(".view").show();
	$target.find(".edit").hide();
});


one operation in multiple event

var $target = $("#target");
$target.on("edit",function(){
	var $this = $(this);
	$this.find(".view").hide();
	$this.find(".edit").show();
});
$target.on("submit",function(){
	//validation
	//submit	
});
$target.on("cancel",function(){
	$target.find(".view").show();
	$target.find(".edit").hide();
});
$("#btn").click(function(){ $target.trigger("edit"); });
$target.find(".edit .submit").click(function(){ 
    $target.trigger("submit"); 
});
$target.find(".edit .cancel").click(function(){  
	$target.trigger("cancel"); 
});

Variable name conflict

var item = $(".item");
for(var i = 0 ,len = item.length ; i < len ; ++i){
    /*........*/
	var details = item.eq(i).find(".details");

    for(var i = 0 , len = details.length; i<len; ++i){
    	/* .... */
    }

}

VARIABLE NAME CONFLICT

var k = 1;
function test(){
	console.log(k); //expect 1 but print undefined ,
	var k = 5;
	console.log(k);	
}
test();

Scope

var item = $(".item");
for(var i = 0 ,len = item.length; i<len ;++i){
	item.eq(i).click(function(){
		alert(i);
	});
}
//When it got trigger , i is always item.length
test(); //expect error but it print "hi"

function test(){
	console.log("hi");
}

Null issue

function test(options){
	//oops , options is undefined
	var k = options.position.x;
}
function test(options){
	options = $.extend({},options);
}
function test(options){
	options = options || {};
}
function test(options){
	if(options != null && options.position != null){
		var k = options.position.left;
	}
}
function test(options){
	var position = (options && options.position) 
		|| {left:null,top:null};
}

Other Useful pattern


  • Scope Protection
  • Pub-sub pattern (wiki
  • Prevent Browser Repaint 
  • Plugin template
  • Template Issue
  • AMD (RequireJS)
  • Promise Pattern

Scope Protection

Limit your variable scope as need.

To prevent NAMING CONFLICT by default.

(function($,/*...*/,undefined){
      var k = 1;
})(jQuery,/*other global objects*/);

console.log(k);//You can't access k here.

scope protection

(function($,undefined){

   var user = ""; //scope is protected in local
   window.item = ""; //global variable

})(jQuery);
console.log(user);// undefined , you can't access it here.

SCOPE PROTECTION

If you want to use global variable , DECLARE it .

  • Write the global object explicitly 
  • Use upper case variable name
  • Use function instead of properties if possible

Scope Protection

window.User = {  
	name : "Tony" , 
	State :"Logined" 
};
window._user ={
	name : "Tony" , 
	State :"Logined" 
};
window.getUser = function(){
	return this._user;
}

Pub-sub pattern


  • Decoupled event trigger and listener
  • Encapsulation the implementation

Use jQuery custom event to implement it.

                Global event -> document or global object ($({}))
                Dom-based event -> dom 

Prevent Browser Repaint 

Prevent a lot of dom changes in a loop or timer.
Use css class instead of changing dom style properties.
var users = ["user1", /*.......*/ ,"user999"],
	table = $("#table");
for(var i= 0 ,len = user.length ; i < len ;++i){
	table.append("<tr><td>"+user[i]+"</td></tr>");
}
vs
var users = ["user1", /*.......*/ ,"user999"],
	table = $("#table"),
	out = [];
for(var i= 0 ,len = user.length ; i < len ;++i){
	out.push("<tr><td>"+user[i]+"</td></tr>");
}
table.append(out.join(""));

Plugin template


(function ($,undefined) {  
    $.fn.myplugin = function (opts) {
        // default configuration
        opts = $.extend({},opts);
        // main function
        var init = function (obj) {
        };
        // initialize every element
        this.each(function () {
            init($(this));
        });
        return this;
    };
    // auto start
    $(function () {
        $('.myplugin').myplugin();
    });
})(jQuery);

Template Issue

How to write html in JS?

<script type="text/template" id="user-tmp"></script>
<textarea id="user-tmp">(htmlescaped content) </textarea/>
var js = (json_encode content);
var js = '<div> '+myobj.name + '</div>';

AMD (RequireJS)

Stop maintaining <Script> tag EVERY PAGE.
Use define / require to load Lib dynamic.
<script src="jquery.js"></script>
<!-- <script src="jquery.min.js"></script>-->
<script src="jquery.ui.js"></script>
<script src="jquery.form.js"></script>
<script src="jquery.validations.js"></script>
<script src="page.js"></script>
vs
<script src="require-jquery.js" main="page"></script>
require(["jquery","jquery.ui","jquery.form","jquery.validations"],
	function($){
	   //content of page js
	}
);

Promise Pattern

It's easy to get confused by the API.
Separated event publish and handler. 

"When to ready" => Deferred
"Handler" => Promise

Just like "Ready" event.

PROMISE PATTERN


When we call

//as same as $(document).ready(function(){});
$(function(){ 
alert("hi");
}); 
It's usually "NOT READY" yet, 
but we know it will be invoked after page ready.

(That's how document said.)

PROMISE PATTERN


What if we implement with Deferred?

Count down example :
function countdown(ms){
    var time = $.Deferred();
    setTimeout(function(){
        time.resolve();
    },ms);
    return time.promise();
}
countdown(5000).done(function(){
     alert("5 seconds, timeout!");
});
http://jsfiddle.net/vsNnq/

Q & A 


Any questions ?





Thanks   


You could find slides on JavaScript.tw FB group.

jquery reminder

By TonyQ Wang

jquery reminder

  • 5,515