高程之高級技巧

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;

}();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末同规,一起剝皮案震驚了整個濱河市循狰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌券勺,老刑警劉巖绪钥,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異关炼,居然都是意外死亡程腹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門儒拂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寸潦,“玉大人,你說我怎么就攤上這事社痛〖” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵蒜哀,是天一觀的道長池户。 經(jīng)常有香客問我,道長凡怎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任赊抖,我火速辦了婚禮统倒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘氛雪。我一直安慰自己房匆,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布报亩。 她就那樣靜靜地躺著浴鸿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弦追。 梳的紋絲不亂的頭發(fā)上岳链,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音劲件,去河邊找鬼掸哑。 笑死约急,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的苗分。 我是一名探鬼主播厌蔽,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摔癣!你這毒婦竟也來了奴饮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤择浊,失蹤者是張志新(化名)和其女友劉穎戴卜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體近她,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡叉瘩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粘捎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薇缅。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攒磨,靈堂內(nèi)的尸體忽然破棺而出泳桦,到底是詐尸還是另有隱情,我是刑警寧澤娩缰,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布灸撰,位于F島的核電站,受9級特大地震影響拼坎,放射性物質(zhì)發(fā)生泄漏浮毯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一泰鸡、第九天 我趴在偏房一處隱蔽的房頂上張望债蓝。 院中可真熱鬧,春花似錦盛龄、人聲如沸饰迹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啊鸭。三九已至,卻和暖如春匿值,著一層夾襖步出監(jiān)牢的瞬間赠制,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工挟憔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憎妙,地道東北人库正。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像厘唾,于是被迫代替她去往敵國和親褥符。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法抚垃,類相關(guān)的語法喷楣,內(nèi)部類的語法,繼承相關(guān)的語法鹤树,異常的語法铣焊,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)罕伯,斷路器曲伊,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 校園音樂短劇 為你千千萬萬遍 【人物】 王明亮:11歲男孩,小學(xué)生追他,自閉癥 班長:王明亮同學(xué)坟募,成績優(yōu)秀,有主見富有...
    蕾蕾lcm閱讀 706評論 0 1
  • 早邑狸,今天的公交依然很擠懈糯,大概因為昨天下過一場雨的緣故,雖然是周二单雾,路上卻異常擁堵赚哗。而你,是否就在這艱難前行的人流之...
    七點七分田閱讀 167評論 0 0
  • 有時候突然而來的事件會刷新我們的認知 對于自己不想接受的事情 真的一點都不想要勉強去接受一絲一毫 有時候突然而來的...
    小海是個夢想家閱讀 288評論 0 0