Javascript Tips & Tricks
2015-02-20 05:54
417 查看
前端开发规范系列文章之Javascript Tips and Tricks,本意是写成常用代码收集、常用技巧整理的文章,感觉“常用代码大全”太土、“实用代码整理”有失偏颇,“提示与技巧”不够稳重,所以使用常用的英语说法,相信广大程序员都懂得。
博主会不断更新本文,方便大家阅读起见,我们采用倒序更新的方式,把最新更新的放最上方。
shim将新的api引入新的环境中,例如下面的代码使用addEvent和removeEvent来添加删除事件。
polyfill让旧浏览器支持新功能,使用方式和标准浏览器一样,例如下面的EventListener polyfill在IE9-浏览器上实现addEventListener、removeEventListener、dispatchEvent和customEvent等。
但是这种方式执行效率比较低,我还需探索更为高效的置乱方式。
这种方式已经比较高效,但是可控性不强,不能指定随机方法,我们又进行了改进。
运行结果为: undefined,你猜对了吗?我们接下来看看为啥?
悬挂,也即所有函数体内的变量声明(注意,仅仅是声明)都将被提到函数体开头进行。所以上面这段代码实际上是这样执行的。
模拟块作用域,避免污染全局变量,常见的插件即是如此。
解决闭包冲突,我们知道闭包可以让“函数内部所定义的函数持有外层函数的执行环境”,然而也有可能有些问题,例如下面的代码。
我们可以使用IIFE解决这个问题,修正过的代码如下。
模拟单例,javascript中我们可以使用IIFE实现OOP。
配合逻辑运算符使用,例如addEventListener的polyfill可以这么写。
45 Useful JavaScript Tips, Tricks and Best Practices
12 Simple (Yet Powerful) JavaScript Tips
13 JavaScript Tips & Tricks
21 JavaScript Tips And Tricks For JavaScript Developers
CSS-Tricks Javascript Snippets
JavaScript Snippets
JavaScript Snippets
5 Array Methods That You Should Be Using Now
JS-Tricks
ten-useful-javascript-tips-best-practices
javascript-performance-tips-tricks
Superpower your JavaScript with 10 quick tips - For Beginners
欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接,/article/1328221.html
欢迎大家访问独立博客http://whqet.github.io
妙味
Javascript美妙之处,需要我们静静体会,慢慢吸收,然后让代码在您指下曼舞。整理的这些代码我们称之为妙味,请大家细品。博主会不断更新本文,方便大家阅读起见,我们采用倒序更新的方式,把最新更新的放最上方。
事件处理
我们知道IE和标准浏览器在事件处理方面有很大不同,所以我们在使用的时候需要首先进行统一化处理,统一处理时有两种方式,shim和polyfill。shim将新的api引入新的环境中,例如下面的代码使用addEvent和removeEvent来添加删除事件。
// Shim for DOM Events for IE7- // http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html // Use addEvent(object, event, handler) instead of object.addEventListener(event, handler) window.addEvent = function(obj, type, fn) { if (obj.addEventListener) { obj.addEventListener(type, fn, false); } else if (obj.attachEvent) { obj["e" + type + fn] = fn; obj[type + fn] = function() { var e = window.event; e.currentTarget = obj; e.preventDefault = function() { e.returnValue = false; }; e.stopPropagation = function() { e.cancelBubble = true; }; e.target = e.srcElement; e.timeStamp = Date.now(); obj["e" + type + fn].call(this, e); }; obj.attachEvent("on" + type, obj[type + fn]); } }; window.removeEvent = function(obj, type, fn) { if (obj.removeEventListener) { obj.removeEventListener(type, fn, false); } else if (obj.detachEvent) { obj.detachEvent("on" + type, obj[type + fn]); obj[type + fn] = null; obj["e" + type + fn] = null; } };
polyfill让旧浏览器支持新功能,使用方式和标准浏览器一样,例如下面的EventListener polyfill在IE9-浏览器上实现addEventListener、removeEventListener、dispatchEvent和customEvent等。
// EventListener | CC0 | github.com/jonathantneal/EventListener this.Element && Element.prototype.attachEvent && !Element.prototype.addEventListener && (function () { function addToPrototype(name, method) { Window.prototype[name] = HTMLDocument.prototype[name] = Element.prototype[name] = method; } // add addToPrototype("addEventListener", function (type, listener) { var target = this, listeners = target.addEventListener.listeners = target.addEventListener.listeners || {}, typeListeners = listeners[type] = listeners[type] || []; // if no events exist, attach the listener if (!typeListeners.length) { target.attachEvent("on" + type, typeListeners.event = function (event) { var documentElement = target.document && target.document.documentElement || target.documentElement || { scrollLeft: 0, scrollTop: 0 }; // polyfill w3c properties and methods event.currentTarget = target; event.pageX = event.clientX + documentElement.scrollLeft; event.pageY = event.clientY + documentElement.scrollTop; event.preventDefault = function () { event.returnValue = false }; event.relatedTarget = event.fromElement || null; event.stopImmediatePropagation = function () { immediatePropagation = false; event.cancelBubble = true }; event.stopPropagation = function () { event.cancelBubble = true }; event.target = event.srcElement || target; event.timeStamp = +new Date; // create an cached list of the master events list (to protect this loop from breaking when an event is removed) for (var i = 0, typeListenersCache = [].concat(typeListeners), typeListenerCache, immediatePropagation = true; immediatePropagation && (typeListenerCache = typeListenersCache[i]); ++i) { // check to see if the cached event still exists in the master events list for (var ii = 0, typeListener; typeListener = typeListeners[ii]; ++ii) { if (typeListener == typeListenerCache) { typeListener.call(target, event); break; } } } }); } // add the event to the master event list typeListeners.push(listener); }); // remove addToPrototype("removeEventListener", function (type, listener) { var target = this, listeners = target.addEventListener.listeners = target.addEventListener.listeners || {}, typeListeners = listeners[type] = listeners[type] || []; // remove the newest matching event from the master event list for (var i = typeListeners.length - 1, typeListener; typeListener = typeListeners[i]; --i) { if (typeListener == listener) { typeListeners.splice(i, 1); break; } } // if no events exist, detach the listener if (!typeListeners.length && typeListeners.event) { target.detachEvent("on" + type, typeListeners.event); } }); // dispatch addToPrototype("dispatchEvent", function (eventObject) { var target = this, type = eventObject.type, listeners = target.addEventListener.listeners = target.addEventListener.listeners || {}, typeListeners = listeners[type] = listeners[type] || []; try { return target.fireEvent("on" + type, eventObject); } catch (error) { if (typeListeners.event) { typeListeners.event(eventObject); } return; } }); // CustomEvent Object.defineProperty(Window.prototype, "CustomEvent", { get: function () { var self = this; return function CustomEvent(type, eventInitDict) { var event = self.document.createEventObject(), key; event.type = type; for (key in eventInitDict) { if (key == 'cancelable'){ event.returnValue = !eventInitDict.cancelable; } else if (key == 'bubbles'){ event.cancelBubble = !eventInitDict.bubbles; } else if (key == 'detail'){ event.detail = eventInitDict.detail; } } return event; }; } }); // ready function ready(event) { if (ready.interval && document.body) { ready.interval = clearInterval(ready.interval); document.dispatchEvent(new CustomEvent("DOMContentLoaded")); } } ready.interval = setInterval(ready, 1); window.addEventListener("load", ready); })(); !this.CustomEvent && (function() { // CustomEvent for browsers which don't natively support the Constructor method window.CustomEvent = function CustomEvent(type, eventInitDict) { var event; eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined}; try { event = document.createEvent('CustomEvent'); event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail); } catch (error) { // for browsers which don't support CustomEvent at all, we use a regular event instead event = document.createEvent('Event'); event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable); event.detail = eventInitDict.detail; } return event; }; })();
置乱数组
Javascript中置乱数组的一种方式,sort方法可以接受一个 函数为参数,当函数返回值为1的时候就交换两个数组项的顺序,否则就不交换。如下代码所示。yourArray.sort(function() { return 0.5 - Math.random() });
但是这种方式执行效率比较低,我还需探索更为高效的置乱方式。
/* 添加原型方法的方式 */ Array.prototype.shuffle = Array.prototype.shuffle || function(){ for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x); return this; };
这种方式已经比较高效,但是可控性不强,不能指定随机方法,我们又进行了改进。
/* 带参数的置乱数组原型方法 * copy默认值为false,copy为true时 ,返回置乱的数组,不影响数组本身 * rng为置乱函数,默认为Math.random * */ Array.prototype.shuffle = Array.prototype.shuffle || function(copy, rng){ var that = this, //保证原数组不受影响 i = this.length, //循环指针,初始值为数组长度 r, //随机数 t; //交换时的临时变量 copy = copy || false; //参数默认值 rng = rng || Math.random; copy&&(that=this.slice()); //copy为true时,生成新的数组that while(i){ r = Math.floor(rng() * i); //生成随机数 t=that[--i]; //交换数值 that[i]=that[r]; that[r]=t; } return that; //返回置乱后数组 }
删除字符串中的空格(Trim String)
es5中具有删除空格的原生方法String.trimLeft()、 String.trimRight()和 String.trim(),这些方法在标准浏览器中兼容性良好,trim方法在ie 9+兼容良好,trimLeft和trimRight在IE中不兼容,不兼容的浏览器我们需要使用polyfill。/* e5中trim方法的polyfill */ String.prototype.trim = String.prototype.trim || function () { return this.replace(/^\s+|\s+$/g, ""); }; String.prototype.trimLeft = String.prototype.trimLeft || function () { return this.replace(/^\s+/, ""); }; String.prototype.trimRight = String.prototype.trimRight || function () { return this.replace(/\s+$/, ""); }; String.prototype.trimFull = String.prototype.trimFull || function () { return this.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g, "").replace(/\s+/g, " "); }; //使用 " hello world ".trimRight(); //" hello world" " hello world ".trimLeft(); //"hello world " " hello world ".trim(); //"hello world" " hello world ".trimFull(); //"hello world"
检测html标签属性
有的时候我们想知道某个元素是否具备某属性,我们可以使用该函数检测。//检测属性 function elementSupportsAttribute(element, attribute) { var test = document.createElement(element); if (attribute in test) { return true; } else { return false; } } //简化版检测属性 function elementSupportsAttribute(element, attribute) { return !!(attribute in document.createElement(element)); }; //使用,检测textarea元素的placeholder属性 elementSupportsAttribute("textarea", "placeholder")?alert("ok"):alert("not");
尽量使用“===”
在javascript中,==和===都表示相等,但是==会在需要的时候进行类型转换,而===则不会进行类型转换,会比较数据类型和数据数值,比==执行速度快。[10] === 10 // is false [10] == 10 // is true '10' === 10 // is false '10' == 10 // is true [] === 0 // is false [] == 0 // is true '' === false // is false '' == false // is true but true == "a" is false
悬挂(Hoisting)
首先来看段代码,大家先猜下运行结果。var a = 1; function go(){ console.log(a); var a = 2; } go();
运行结果为: undefined,你猜对了吗?我们接下来看看为啥?
悬挂,也即所有函数体内的变量声明(注意,仅仅是声明)都将被提到函数体开头进行。所以上面这段代码实际上是这样执行的。
var a; a = 1; function go(){ var a; console.log(a); a = 2; } go();
立即调用函数表达式(IIFE)
立即调用函数表达式(IIFE, Immediately Invoked Function Expressions)是Javascript里面常用特性,我们可以利用它“避免污染全局变量”、“解决闭包冲突”、“只执行一次的函数”、“减少重复创建比较大的对象的开销(常见在一些工具函数内部,保存正则对象,数组,长字符串等对象”等。/*简化版的IIFE*/ (function(){ //您的代码 })();
模拟块作用域,避免污染全局变量,常见的插件即是如此。
/* jquery1.9.0的写法 */ (function( window, undefined ) { //非常长的代码 })( window );
解决闭包冲突,我们知道闭包可以让“函数内部所定义的函数持有外层函数的执行环境”,然而也有可能有些问题,例如下面的代码。
var f1 = function() { var res = []; var fun = null; for(var i = 0; i < 10; i++) { fun = function() { console.log(i);};//产生闭包 res.push(fun); } return res; } // 会输出10个10,而不是预期的0 1 2 3 4 5 6 7 8 9 var res = f1(); for(var i = 0; i < res.length; i++) { res[i](); }
我们可以使用IIFE解决这个问题,修正过的代码如下。
var f1 = function() { var res = []; for(var i = 0; i < 10; i++) { // 添加一个IIFE,立即执行 (function(index) { fun = function() {console.log(index);}; res.push(fun); })(i); } return res; } // 输出结果为0 1 2 3 4 5 6 7 8 9 var res = f1(); for(var i = 0; i < res.length; i++) { res[i](); }
模拟单例,javascript中我们可以使用IIFE实现OOP。
var counter = (function(){ var i = 0; return { get: function(){ return i; }, set: function( val ){ i = val; }, increment: function() { return ++i; } }; }()); counter.get(); // 0 counter.set( 3 ); counter.increment(); // 4 counter.increment(); // 5
配合逻辑运算符使用,例如addEventListener的polyfill可以这么写。
/*把IIFE和逻辑运算符配合使用,检测是否需要运行polyfill*/ this.Element && Element.prototype.attachEvent && !Element.prototype.addEventListener && (function () { //polyfill }
逻辑运算符妙用
使用&&和||条件运算符,我们可以达到简化操作的目的,来看下面代码。/* code one */ if (!theTitle) { theTitle = "Untitled Document"; } //使用|| theTitle = theTitle || "Untitled Document"; /* code two */ function isAdult(age) { if (age && age > 17) { return true; } else { return false; } } //使用 && function isAdult(age) { return age && age > 17 ; } /* code three*/ if (userName) { logIn (userName); } else { signUp (); } //混合使用&&、|| userName && logIn (userName) || signUp (); /*code four*/ var userID; if (userName && userName.loggedIn) { userID = userName.id; } else { userID = null; } //使用&&、|| var userID = userName && userName.loggedIn && userName.id
深入
本文的写作过程大量参考了以下文章,大家可以仔细阅读下面文章获得更深的体会。45 Useful JavaScript Tips, Tricks and Best Practices
12 Simple (Yet Powerful) JavaScript Tips
13 JavaScript Tips & Tricks
21 JavaScript Tips And Tricks For JavaScript Developers
CSS-Tricks Javascript Snippets
JavaScript Snippets
JavaScript Snippets
5 Array Methods That You Should Be Using Now
JS-Tricks
ten-useful-javascript-tips-best-practices
javascript-performance-tips-tricks
Superpower your JavaScript with 10 quick tips - For Beginners
声明
前端开发whqet,关注前端开发,分享相关资源。csdn专家博客,王海庆希望能对您有所帮助,限于作者水平有限,出错难免,欢迎拍砖!欢迎任何形式的转载,烦请注明装载,保留本段文字。
本文原文链接,/article/1328221.html
欢迎大家访问独立博客http://whqet.github.io
相关文章推荐
- (Tips&Tricks)用客户端模板精简JavaScript代码
- ASP.NET AJAX Advance Tips & Tricks (3) JavaScript与Tab的交互
- The JavaScript Anthology: 101 Essential Tips, Tricks & Hacks
- QTP 8.2 FAQ, Tips & Tricks
- Tips&Tricks系列二:找不到Asp.net模板?
- Microsoft Office Excel 2007: Top 100 Simplified Tips & Tricks
- (Tips &amp;Tricks)如何为Windows Mobile 创建拨号连接--C#
- Emacs tips & tricks
- Tips&Tricks系列八:Fail to convert .vsmid,.testrunconfig
- Windows Vista Tips &Tricks
- Fedora Tips & Tricks
- Tips&Tricks系列六:ADO.NET OracleConnection.ClearPool(conn)
- iBATIS.NET Tips & Tricks(1) : 使用Nullable类型
- Eclipse Tips &amp; Tricks-Eclipse 快捷键汇总
- Cool Tips and Tricks with ASP.NET 2.0 posted by Scott
- Adobe Photoshop CS3: Top 100 Simplified Tips & Tricks
- iBATIS.NET Tips & Tricks(2) : 将image列设置为null值时遇到的Operand type clash异常。
- Visual Studio Tips & Tricks
- ASP.NET AJAX Advance Tips & Tricks (3) JavaScript与Tab的交互
- JavaScript tips and tricks - 2