$('#wrapper').click(function(e) { console.log('#wrapper'); console.log(e.currentTarget); console.log(e.target); }); $('#inner').click(function(e) { console.log('#inner'); console.log(e.currentTarget); console.log(e.target); });
结果输出
#inner <a href="#" id="inner">click here!</a> <a href="#" id="inner">click here!</a> #wrapper <div id="wrapper"><a href="#" id="inner">click here!</a></div> <a href="#" id="inner">click here!</a>
写法三(原生写法)
主体结构
var MemberCard = function(_aoOption){ // 配置(默认是从外面传进来) _aoOption || (_aoOption = {}) ; // 初始化函数 _init(this); } var _init = function(_aoSelf) { // 函数执行 _initData(_aoSelf); // 调用对象的私有方法 _aoSelf._timedHide(); } var _initData = function ( _aoSelf ) {} // 私有方法 MemberCard.prototype._timedHide = function(_aoOptions) { var _oSelf = this; clearTimeout(this.iHideTimer); // 使用underscore.js的extend方法来实现属性覆盖 var oDefault = extend( { nHideTime: 300 }, _aoOptions ); _oSelf.iHideTimer = setTimeout( function(){ // 调用对象的共有方法 _oSelf.hide(); }, oDefault.nHideTime); } // 公有方法 MemberCard.prototype.hide = function(_aoOptions) {}
使用
var oColleagueCard = new MemberCard({ nHideTime: 200 }); oColleagueCard.hide();
点评:
1. 关于属性覆盖(对象深拷贝)
原生函数实现方法
function getType(o){ return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase(); } function extend(destination,source){ for(var p in source){ if(getType(source[p])=="array"||getType(source[p])=="object"){ destination[p]=getType(source[p])=="array"?[]:{}; arguments.callee(destination[p],source[p]); }else{ destination[p]=source[p]; } } }
demo:
var test={a:"ss",b:[1,2,3],c:{d:"css",e:"cdd"}}; var test1={}; extend(test1,test); test1.b[0]="change"; //改变test1的b属性对象的第0个数组元素 alert(test.b[0]); //不影响test,返回1 alert(test1.b[0]); //返回change
基于jQuery的实现方法:
jQuery.extend([deep], target, object1, [objectN]);
用一个或多个其他对象来扩展一个对象,返回被扩展的对象。
如果不指定target,则给jQuery命名空间本身进行扩展。这有助于插件作者为jQuery增加新方法。 如果第一个参数设置为true,则jQuery返回一个深层次的副本,递归地复制找到的任何对象。否则的话,副本会与原对象共享结构。 未定义的属性将不会被复制,然而从对象的原型继承的属性将会被复制。
demo:
var options = {id: "nav", class: "header"} var config = $.extend({id: "navi"}, options); //config={id: "nav", class: "header"}
2. 关于this
这个对象的所有方法的this都指向这个对象,所以就不需要重新指定
写法四
主体结构
function EditorUtil() { this._editorContent = $( '#editor_content' ); this._picBtn = $( '#project_pic' ); this.ieBookmark = null; } EditorUtil.prototype = { consturctor: EditorUtil, noteBookmark: function() { }, htmlReplace: function( text ) { if( typeof text === 'string' ) { return text.replace( /[<>"&]/g, function( match, pos, originalText ) { switch( match ) { case '<': return '<'; case '>': return '>'; case '&': return '&'; case '"': return '"'; } }); } return ''; }, init: function() { this._memBtn.bind( 'click', function( event ) { $(".error_content").hide(); return false; }); } }; // 初始化富文本编辑器 var editor = new EditorUtil(); editor.init();
总结
写法四和写法三其实都差不多,但是你们有没有看出其中的不一样呢?
两种都是利用原型链给对象添加方法:
写法三:
MemberCard.prototype._timedHide MemberCard.prototype.hide
写法四:
EditorUtil.prototype = { consturctor: EditorUtil, noteBookmark: function(){}, htmlReplace: function(){} }
细看写法四利用“对象直接量”的写法给EditorUtil对象添加方法,和写法三的区别在于写法四这样写会造成consturctor属性的改变
constructor属性:始终指向创建当前对象的构造函数
每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数。如下例所示: