1 、高級函數(shù)
1.1 安全類型檢測
typeof操作符經(jīng)常會檢測數(shù)據(jù)類型不靠譜的結(jié)果眼虱, safari對正則表達式應(yīng)用typeof 返回funtion很難確定類型對不對
或者是檢測json是不是原生的勒虾,還是自定義的全局json對象
解決方法:任何值上調(diào)用Object原生的toString()的方法都會返回一個【Object NativeConstrucorName】格式的字符串停撞,每個類都有一個class屬性這個屬性就指定了上述字符串中的構(gòu)造函數(shù)名
function isArray(value){
"use strict";
return Object.prototype.toString.call(value)=="[object Array]";
}
function isFunction(value) {
"use strict"
return Object.prototype.toString.call(value) == "[object Function]";
}
function isRegExp(value){
"use strict";
return Object.prototype.toString.call(value) == "[object RegExp]";
}
d
1.2 作用域安全的構(gòu)造函數(shù)
構(gòu)造函數(shù)就是一個使用new操作符調(diào)用的函數(shù)县踢,當屬用new調(diào)用時候转绷,構(gòu)造函數(shù)內(nèi)用到的this對象會指向新創(chuàng)建的的對象實例,如下
function Persion(name,age,job) {
"use strict";
this.name = name;
this.age = age;
this.job= job;
}
這段殿雪,用new的時候毫無問題暇咆,但是如果直接調(diào)用呢?
var persion = Persion("baipu",12,"engineer");
這時候就會將這三個參數(shù)掛到window下丙曙,從而出現(xiàn)問題,所以我們需要創(chuàng)建一個作用域安全的構(gòu)造函數(shù)
function Persion(name,age,job) {
"use strict";
if(this instanceof Persion){
this.name = name;
this.age = age;
this.job= job;
}else{
return new Persion(name,age,job);
}
}
怎么樣爸业,這種方法機靈不?
但是如果使用構(gòu)造函數(shù)竊取模式的集成而不使用原型鏈,繼承很有可能被破壞亏镰,
function Polygon(sides){
"use strict";
if(this instanceof Polygon){
this.sides = sides;
this.getArea = function () {
return 0;
}
}else{
return new Polygon(sides);
}
}
function Rectangle(width,height) {
Polygon.call(this,2);
this.width = width;
this.height = height;
this.getArea - function () {
return this.width*this.height;
};
}
var a = new Rectangle(1,2);
console.log(a.sides);
這個時候調(diào)用polygon的方法的環(huán)境的時候扯旷,this是Rectangle而不是自己,所以沒有賦值成功索抓,
如果構(gòu)造函數(shù)竊取使用原生鏈或者寄生組合钧忽,可以解決這個問題:
Rectangle.prototype = new Polygon();
var rect = new Rectangle(5,10);
alert(rect.sides)//2
1.3 惰性載入函數(shù)
多幸哉儒表示函數(shù)執(zhí)行的分支僅會發(fā)生一次。
兩種實現(xiàn)方式:
1逼肯、函數(shù)被調(diào)用時才處理函數(shù)耸黑,也就是說,第一次調(diào)用過程中該函數(shù)會被覆蓋為另外一個按合適方式執(zhí)行的函數(shù)篮幢,
function createXHR() {
if(typeof XMLHttpRequest != "undefined"){
createXHR = function () {
return new XMLHttpRequest();
}
}else if (typeof ActiveXObject !="undefined"){
createXHR = function () {
if(typeof arguments.callee.activeXString != "string"){
var version = [],i,len;
for(i=0,len = version.length;i<len;i++){
}
}
}
}else{
createXHR = function () {
throw new Error("NO XHR object available.")
}
}
}
2大刊、聲明函數(shù)是后就制定適當?shù)暮瘮?shù),這樣第一次調(diào)用函數(shù)是后就不會損失性能了
閉包的方式進行處理:
var createXHR = (function(){
"use strict";
if(typeof XMLHttpRequest != "undefined"){
return function(){
new XMLHttpRequest();
};
}else if(typeof ActiveXObject !="undefined"){
return function () {
//這里是這個情況下的function
}
}else{
return function () {
throw new Error("no xhr object available")
}
}
})();
1.4 函數(shù)綁定
詳情請見bind的用法
1.5 函數(shù)柯里化
柯里化:調(diào)用另一個函數(shù)三椿,并為他傳入要柯里化的函數(shù)和必要參數(shù)
function curry(fn) {
"use strict";
var args = Array.prototype.slice.call(arguments,1);
return function () {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null ,finalArgs);
}
}
2 防篡改對象
Configurable Writable Enumerable Value Get Set以改變其屬性的行為
注意:一旦把對象定義為防篡改缺菌,就無法撤銷
2.1 不可擴展對象:
Object.preventExtensions();
(function () {
"use strict";
var persion = {};
Object.preventExtensions(persion);
persion.age = 11;
console.log(persion.age);//undefined
})()
Object.isExtensible(Persion)//來判斷對象是否可擴展
2.2密封的對象
configurable 不能刪除屬性和方法
var person = {name:"Nicholas"};
Object.seal(person);
person.age = 29;
delete person.name;
console.log(person.age);//undefined 添加失敗
console.log(person.name);//Nocholas//刪除失敗
但是不能在嚴格模式中用
用Object.isSealed()的方法來判斷是否密封
2.3 凍結(jié)的對象
既不可擴張也是密封的,writable為false
Object.freeze(person);
person.age = 20;//console.log undefined
delete person.name// 刪除失敗
person.name = "Greg";//Nicholads修改失敗
3 高級定時
簡單來說就是:setTimeout(function(){},200)表示200秒后搜锰,將function添加到隊列中,而不是多線程處理
3.1 重復(fù)的定時器
使用setInterval()
這個setInterval的問題是可能在代碼再次添加到隊列之前還沒有完成執(zhí)行伴郁,導(dǎo)致定時器代碼連續(xù)運行好幾次,之間沒有任何停頓蛋叼,使用setInterval的時候僅僅當沒有改定時器的任何其他代碼示例時候焊傅,才將定時器代碼添加到隊列中,確保了定時器代碼加入到隊列中的最小時間間隔為指定間隔
3.2鸦列、Yielding Processes
function chunk(array,process ,context) {
setTimeout(function () {
var item = array.shift();
process.call(context,item);
if(array.length>0){
setTimeout(arguments.callee,100);
}
},100);
}
3.3 函數(shù)節(jié)流
基本思想:某些代碼不可以在沒有間斷的情況連續(xù)重復(fù)執(zhí)行租冠,第一次調(diào)用函數(shù),創(chuàng)建一個定時器薯嗤,在制定的時間間隔之后運行代碼顽爹,第二次調(diào)用該函數(shù)術(shù)后,他會清除前一次定時器骆姐,并設(shè)值另一個镜粤。如果前一個定時器已經(jīng)執(zhí)行過了捏题,這個操作就沒有任何意義。
應(yīng)對連續(xù)不斷的調(diào)整界面肉渴,然后進行的修改,就好比onresize的時候公荧,會連續(xù)不斷的執(zhí)行:
function throttle(method,context) {
clearTimeout(method.tId);
method.tId = setTimeout(function () {
method.call(context);
},100)
}
function resizeDiv() {
var div = document.getElementById("myDiv");
div.style.height = div.offsetWidth+"px";
}
window.onresize = function () {
throttle(resizeDiv)
};
4 自定義事件
function EventTarget() {
this.handlers = {};
}
EventTarget.prototype = {
constructor:EventTarget,
addHandler:function (type,handler) {
if(typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
}
this.handlers[type].push(handler)
},
fire:function (event) {
if(!event.target){
event.target = this;
}
if (this.handler[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for(var i=0,len=handlers.length;i<len;i++){
handlers[i](event);
}
}
},
removeHandler:function (type,handler) {
if(this.handlers[type] instanceof Array){
var handlers = thsi.handlers[type];
for(var i=0,len=handlers.length;i<len;i++){
if(handlers[i]==handler){
break;
}
}
handlers.splice(i,1);
}
}
};
以下是寄生組合繼承:
function Person(name,age) {
EventTarget.call(this);
this.name = name;
this.age =age;
}
inheritPrototype(Person,EventTarget);
Person.prototype.say = function (message) {
this.fire({type:"message",message:message})
};
function handleMessage(event) {
alert(event.target.name+"says:"+event.message);
}
var person = new Person("Nicholas",30);
person.say("Hi there .");
5.跨瀏覽器的事件對象
// 跨瀏覽器的事件對象
var EventUtil = {
addHandler:function (element,type,handler) {
//省略的代碼
if(element.addEventListener){
element.addEventListener(type,handler,false);//使用dom2級方法添加事件
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type] = handler;
}
},
getEvent:function (event) {
return event?event:window.event;
},
getTarget:function (event) {
return event.target||event.srcElement;
},
preventDefault:function (event) {
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
removeHandler:function (element, type, handler) {
//todo:remove the handler
if(element.removeEventListener){
element.removeEventListener(type,handler,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
}else{
element["on"+type] = null;
}
},
stopPropagation:function (event) {
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
},
getRelatedTarget:function (event) {//mouseover mouseout
if(event.relateTarget){
return event.relateTarget;
}else if(event.toElement){
return event.toElement;
}else if(event.formElement){
return event.fromElement;
}else{
return null;
}
},
getButton :function (event) {//獲取mousedown 或者是mouseuo按下或釋放的按鈕式鼠標中的哪一個
if(document.implementation.hasFeature("MouseEvents","2.0")){
return event.button;
}else{
switch (event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;//摁下的是主按鈕
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
},
getWheelDelta:function (event) {//滾輪滾動的方向
if(event.wheelDelta){
return event.wheelDelta;
}else{
return -event.detail*40
}
},
getCharCode:function (event) {//keypress取得相同的字符編碼
if(typeof event.charCode == "number"){
return event.charCode;
}else{
return event.keyCode;
}
}
};
6、拖放:
EventUtil.addHandler(document,"mousemove",function (event) {
var myDiv = document.getElementById("myDiv");
myDiv.style.left = event.clientX+"px";
myDiv.style.top= event.clientY+"px";
});
var DragDrop = function () {
var dragdrop = new EventTarget(),
dragging =null,
diffx = 0,
diffy = 0;
function handleEvent(event) {
event = EventUtil.getTarget(event);
var target = EventUtil.getTarget(event);
switch (event.type){
case "mousedown":
if (target.className.indexOf("draggable")>-1){
dragging = target;
diffx = event.clientX-target.offsetLeft;
diffy = event.clientY - target.offsetTop;
dragdrop.fire({
type:"dragstart",
target:dragging,
x:event.clientX,
y:event.clientY
});
}
break;
case "mouseove":
if(dragging !=null){
dragging.style.left = (event.clientX- diffx)+"px";
dragging.style.top = (event.clientY-diffy)+"px";
dragdrop.fire({
type:"drag",
target:dragging,
x:event.clientX,
y:event.clientY
})
}
break;
case "mouseup":
dragdrop.fire({
"type":"draggend",
target:dragging,
x:event.clientX,
y:event.clientY
});
dragging = null;
break;
}
}
dragdrop.enable = function () {
EventUtil.addHandler(document,"mousedown",handleEvent);
EventUtil.addHandler(document,"mousemove",handleEvent);
EventUtil.addHandler(document,"mouseup",handleEvent);
};
dragdrop.disable = function () {
EventUtil.removeHandler(document,"mousedown",handleEvent);
EventUtil.removeHandler(document,"mousemove",handleEvent);
EventUtil.removeHandler(document,"mouseup",handleEvent);
}
return dragdrop;
}();