JS基礎之經常使用小技巧和知識總結(一)

本文主要記錄平時開發遇到的知識點和小技巧javascript


相等判斷(==)

類型相同: 判斷其值是否相同java

類型不一樣:android

1. 若是數字和字符串比較, 則字符串會被隱式轉換爲數字,在作判斷。
 2. 若是有一方是布爾值, 則true 轉換爲 1, false 轉換爲 0 ,再進行判斷。
 3. 若是其中有一個值爲對象, 則對象會調取自身的valueOf 或者toString方法進行轉換,再作判斷。
 4.undefined 與 null 相等。

等同運算符(===)

類型不一樣: 返回false
類型相同: 

    1. 若是同爲數字/字符串, 則比較值
    2. 若是同爲布爾值, 相同則爲true, 不一樣爲false
    3.  若是兩個操做數同爲引用類型,且引用的爲同一個對象(函數,數組),則相同。

因此使用 === 進行邏輯判斷的時候,本身就要很清楚兩邊的數據類型。 好比調用函數獲得的是字符串'1', 與 數字 1 比較的時候,獲得的false, 不要犯相似的低級錯誤。編程

this指針

javascript中, this表示當前上下文, 即調用者的引用。segmentfault

var tom = {
            sex: 'M',
            age: 20
        }


        var jerry = {
            sex: 'F',
            age: 18
        }

        function getAge() {
            return this.age;
        }

        console.log(getAge.call(tom)); // 20
        console.log(getAge.call(jerry)); // 18

        // 經過call 方法, 改變了getAge函數中this的指向, this不會指向getAge函數自己。
        


        var person = {
            first: 'john',
            last: 'tom',
            getFull: function () {
                console.log(this.first + ' ' + this.last);
            }
        }

        person.getFull(); // john tom 
        //this 指向person


        var firstName = 'will';
        var lastName = 'smith';

        function getFull() {
            console.log(this.firstName + ' ' + this.lastName);
        }

        getFull(); // will smith
        //調用者是window,因此 this 指向window。

        function a() {
            console.log(this);
        }
        a.call(null);

call 調用一個對象的一個方法,以另外一個對象替換當前對象。 數組

格式如 call(thisObj, arg1,arg2...argN);瀏覽器

在函數體外部調用call()方法,若是傳入null,則默認轉成window,若是不傳也是同樣,即函數中的this指向window。
console.log(this) // window;閉包

function a() {
            console.log(this === window);
        }

        console.log(this === window); // true

        a.call(); // true
        a.call(null); // true
        a.call(this); // true
        a.call(window); // true
        a(); // true

this 的值並不是取決於如何被定義, 而是取決於調用方式
更多有關函數調用的內容請翻閱javascript語言精粹第四章的函數部分。
更多有關this的內容能夠翻閱《你不知道的javascript上卷》第二章。app

變量聲明與函數聲明提高

JavaScript會將全部變量和函數聲明移動到它的做用域的最前面,這就是所謂的變量提高(Hoisting)。函數

也就是說,不管你在什麼地方聲明變量和函數,解釋器都會將它們移動到做用域的最前面。所以咱們能夠先使用變量和函數,然後聲明它們.

可是,僅僅是變量聲明被提高了,而變量賦值不會被提高。

若是你不明白這一點,有時則會出錯:

console.log(a);  // 輸出undefined
a = 2; // 初始化y

// 上面的代碼等同於
var a;  // 聲明y
console.log(a);  // 輸出undefined
a = 2; // 初始化y

再看一個:

var a;

console.log(a);

a = 1;

function a() {
    // xxx
}

輸出:
/*

function a() {
    // xxx
}
1
*/

javascript永遠是先解析聲明函數,再解析變量。

執行順序以下:
(1) 解析函數a;
(2) 聲明變量var a; 由於a此時並無被賦值,因此它爲 undefined, 仍是指向原來的值,即函數 function a;
(3) console.log(a); // function a
(4) a = 1; // 從新賦值, 輸出1

函數重載

javascript中是沒有函數重載的,可是javascript的函數沒有限制傳入的參數個數必須與函數接收參數的個數相同,因此咱們能夠利用這一特性來模擬函數重載。

舉個栗子:

function add() {
            if (arguments.length < 2) {
                return arguments[0];
            } else {
                var _args = [].slice.call(arguments);
                return _args.reduce(function (a, b) {
                    return a + b;
                })
            }
        }

        add(1); // 1
        add(1, 2, 3, 4); // 10

舉個計算日期的栗子:

// ..
        getFutureDate: function(startDate, afterYear, afterMonth, afterDay) {
            var futureDate, year, month, day;

            if (arguments.length === 3) {
                afterDay = arguments[2];
                afterMonth = arguments[1];
                afterYear = arguments[0];
                startDate = new Date(startDate);
            }

            if (arguments.length === 4 && Object.prototype.toString.call(startDate) !== "[object Date]") {
                startDate = new Date(startDate);
        getFutureDate: function (startDate, afterYear, afterMonth, afterDay) {
            var futureDate, year, month, day;

            if (arguments.length === 3) {
                afterDay = arguments[2];
                afterMonth = arguments[1];
                afterYear = arguments[0];
                startDate = new Date(startDate);
            }

            if (arguments.length === 4 && Object.prototype.toString.call(startDate) !== "[object Date]") {
                startDate = new Date(startDate);
            }

            //計算年
            futureDate = startDate.setFullYear(startDate.getFullYear() + parseInt(afterYear));
            futureDate = new Date(futureDate);
            // 計算月
            futureDate = futureDate.setMonth(futureDate.getMonth() + parseInt(afterMonth));
            futureDate = new Date(futureDate);
            // 計算日
            futureDate = futureDate.setDate(futureDate.getDate() + parseInt(afterDay));
            futureDate = (new Date(futureDate));

            year = futureDate.getFullYear();

            month = futureDate.getMonth() + 1;
            month = month < 10 ? '0' + month : month;

            day = futureDate.getDate();
            day = day < 10 ? '0' + day : day;

            futureDate = [year, month, day].join('-');

            return futureDate
        },
         initDateTime: function () {
            // ...
            var endTime = _that.getFutureDate(new Date(today.replace(/-/g, "/")).getTime(), 0, maxInsuranceMonth, maxInsuranceDay);   
            // ...
        }
        // ...

Map 函數

var ary = [1, 2, 3, 4, 5];

    var res = ary.map(function (item, index, input) {
        return item * 10;
    });

    console.log(res); // [10, 20, 30, 40, 50]
    console.log(ary); // [1, 2, 3, 4, 5]

map 函數的實現:

Array.prototype.map = function (func /*, obj */) {
    var len = this.length;
    //check the argument
    if (typeof func != "function") {
        throw new Error("argument should be a function!");
    }
    var res = [];
    var obj = arguments[1];
    for (var i = 0; i < len; i++) {
        //func.call(), apply the func to this[i]
        res[i] = func.call(obj, this[i], i, this);
    }
    return res;
}

map:和forEach很是類似,都是用來遍歷數組中的每一項值的,用來遍歷數組中的每一項;
區別:map的回調函數中支持return返回值;return的是啥,至關於把數組中的這一項變爲啥(並不影響原來的數組,只是至關於把原數組克隆一份,把克隆的這一份的數組中的對應項改變了);

前面已經說過,this會指向調用者,因此this是指向須要用到map函數的數組的。
須要注意的是,map函數是接收2個參數的,第二個參數是第一個參數的函數this指向。

柯里化

柯里化就是預先將函數的某些參數傳入,獲得一個簡單的函數,可是預先傳入的參數被保存在閉包中,所以會有一些奇特的特性。

var adder = function(num) {
    return function(y) {
        return num + y;
    }
}
console.log(adder(1)(100)); // 101
console.log(adder(2)(100)); // 102

更多內容請翻閱上一篇介紹《邂逅函數柯里化》

遞歸

遞歸在編程中會常用,在某些時候,遞歸能夠給咱們減小不少代碼冗餘。
好比咱們的求階乘函數:

function factorial(n) {
    if (n == 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

函數不停的調用自身,來達到不停的向下求值相乘,從而實現階乘求值。代碼邏輯也一目瞭然。


客戶端判斷

var UA = (function (userAgent) {
    var ISOldIOS     = /OS (\d)_.* like Mac OS X/g.exec(userAgent),
        isOldAndroid = /Android (\d.*?);/g.exec(userAgent) || /Android\/(\d.*?) /g.exec(userAgent);

    // 判斷設備是不是IOS7如下
    // 判斷設備是不是android4.5如下
    // 判斷是否iOS
    // 判斷是否android
    // 判斷是否QQ瀏覽器
    return {
        oldIOS    : ISOldIOS ? +ISOldIOS.pop() < 8 : false,
        oldAndroid: isOldAndroid ? +isOldAndroid.pop().substr(0, 3) < 4.5 : false,
        iOS       : /\(i[^;]+;( U;)? CPU.+Mac OS X/.test(userAgent),
        android   : /Android/g.test(userAgent),
        mQQBrowser: /MQQBrowser/g.test(userAgent)
    }
})(navigator.userAgent);
相關文章
相關標籤/搜索