1. 程式人生 > >廖雪峰JS教程學習筆記

廖雪峰JS教程學習筆記

JavaScript筆記

語法

編譯器自動在每個語句的結尾新增 ;

資料型別

JS不區分整數與浮點數,統一用Number表示,NAN表示Not a Number, Infinity表示無限大,表示超過JavaScript的表示範圍,null表示一個“空”的值,它和0以及空字串''不同,0是一個數值,''表示長度為0的字串,而null表示“空”,undefined表示值未定義。事實證明,這並沒有什麼卵用,區分兩者的意義不大,大多數情況用null,undefined僅僅在判斷函式引數是否傳遞的情況下有用。

變數名是大小寫英文、數字、$_的組合,且不能用數字開頭,變數名前不加var代表是全域性變數(不建議使用)

啟用strict模式的方法是在JavaScript程式碼的第一行寫上:
'use strict';

字串

模板字串

如果有很多變數需要連線,用+號就比較麻煩。ES6新增了一種模板字串,表示方法和上面的多行字串一樣,但是它會自動替換字串中的變數:

var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}歲了!`;
alert(message);

需要特別注意的是,字串是不可變的,

  • toUpperCase()把一個字串全部變為大寫
  • toLowerCase()
    把一個字串全部變為小寫
  • indexOf()會搜尋指定字串出現的位置
  • substring(begin,end)返回指定索引區間的子串
var s = 'hello, world';
s.indexOf('world'); // 返回7
s.indexOf('World'); // 沒有找到指定的子串,返回-1
var s = 'hello, world'
s.substring(0, 5); // 從索引0開始到5(不包括5),返回'hello'
s.substring(7); // 從索引7開始到結束,返回'world'

陣列

JavaScript的Array

可以包含任意資料型別
另一種建立陣列的方法是通過Array()函式實現:(不建議使用)
new Array(1, 2, 3); // 建立了陣列[1, 2, 3]
要取得Array的長度,直接訪問length屬性

  • slice(begin,end)就是對應Stringsubstring()版本,它擷取Array的部分元素,然後返回一個新的Array
    String類似,Array也可以通過indexOf()來搜尋一個指定的元素的位置

  • push()Array的末尾新增若干元素,pop()則把Array的最後一個元素刪除掉

  • 如果要往Array的頭部新增若干元素,使用unshift()方法,shift()方法則把Array的第一個元素刪掉

  • splice()方法是修改Array的“萬能方法”,它可以從指定的索引開始刪除若干元素,然後再從該位置新增若干元素

var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 從索引2開始刪除3個元素,然後再新增兩個元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回刪除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只刪除,不新增:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只新增,不刪除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因為沒有刪除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
  • sort()可以對當前Array進行排序,它會直接修改當前Array的元素位置,直接呼叫時,按照預設順序排序

  • reverse()把整個Array的元素給掉個個,也就是反轉

  • concat()方法把當前的Array和另一個Array連線起來,並返回一個新的Array

  • join()方法是一個非常實用的方法,它把當前Array的每個元素都用指定的字串連線起來,然後返回連線後的字串

var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'

如果Array的元素不是字串,將自動轉換為字串後再連線。

物件

訪問屬性是通過.操作符完成的,但這要求屬性名必須是一個有效的變數名。如果屬性名包含特殊字元,就必須用''括起來,用['xxx']來訪問,不推薦使用此種屬性名,訪問不存在的屬性不報錯,而是返回undefined,檢測物件是否擁有某一屬性,可以用in操作符,不過要小心,如果in判斷一個屬性存在,這個屬性不一定是xiaoming的,它可能是xiaoming繼承得到的, 要判斷一個屬性是否是xiaoming自身擁有的,而不是繼承得到的,可以用hasOwnProperty()方法:

var xiaohong = {
    name: '小紅',
    'middle-school': 'No.1 Middle School'
};
xiaohong['middle-school']; // 'No.1 Middle School'
xiaohong['name']; // '小紅'
xiaohong.name; // '小紅'
xiaoming.age; // undefined
xiaoming.age = 18; // 新增一個age屬性
delete xiaoming.age; // 刪除age屬性
'name' in xiaoming; // true
'toString' in xiaoming; // true
xiaoming.hasOwnProperty('toString'); // false

迴圈

for迴圈的一個變體是for ... in迴圈,它可以把一個物件的所有屬性依次迴圈出來, for ... inArray的迴圈得到的是String而不是Number
ES6標準引入了新的iterable型別,ArrayMapSet都屬於iterable型別。
具有iterable型別的集合可以通過新的for ... of迴圈來遍歷。

var a = ['A', 'B', 'C']
a.name = 'Hello';
for (var x in a) {
    alert(x); // '0', '1', '2', 'name'
}

這就是為什麼要引入新的for ... of迴圈
然而,更好的方式是直接使用iterable內建的forEach方法,它接收一個函式,每次迭代就自動回撥該函式,以Array為例:

var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
    // element: 指向當前元素的值
    // index: 指向當前索引
    // array: 指向Array物件本身
    alert(element);
});
  • Map的回撥函式引數依次為value、key和map本身
  • Set與Array類似,但Set沒有索引,因此回撥函式的前兩個引數都是元素本身
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
    alert(value);
});
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
    alert(element);
});

不需要使用全部的引數

STL-Map&Set

初始化Map需要一個二維陣列,或者直接初始化一個空Map。Map具有以下方法:

var m = new Map(); // 空Map
m.set('Adam', 67); // 新增新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 刪除key 'Adam'
m.get('Adam'); // undefined

要建立一個Set,需要提供一個Array作為輸入,或者直接建立一個空Set:

var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.delete(3)
>>> s
{1, 2, 4}

函式

JavaScript還有一個免費贈送的關鍵字arguments,它只在函式內部起作用,並且永遠指向當前函式的呼叫者傳入的所有引數。arguments類似Array但它不是一個Array:

function foo(x) {
    alert(x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log(arguments[i]); // 10, 20, 30
    }
}
foo(10, 20, 30);

實際上arguments最常用於判斷傳入引數的個數
ES6標準引入了rest引數

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 結果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]

foo(1);
// 結果:
// a = 1
// b = undefined
// Array []

rest引數只能寫在最後,前面用...標識,從執行結果可知,傳入的引數先繫結a、b,多餘的引數以陣列形式交給變數rest

作用域

var變數作用域是在函式內部, let變數,const常量作用域是所屬塊

變數提升

JavaScript的函式定義有個特點,它會先掃描整個函式體的語句,把所有申明變數的宣告“提升”到函式頂部

全域性作用域

不在任何函式內定義的變數就具有全域性作用域。實際上,JavaScript預設有一個全域性物件window,全域性作用域的變數實際上被繫結到window的一個屬性

名字空間

全域性變數會繫結到window上,不同的JavaScript檔案如果使用了相同的全域性變數,或者定義了相同名字的頂層函式,都會造成命名衝突,並且很難被發現。
減少衝突的一個方法是把自己的所有變數和函式全部繫結到一個全域性變數中。例如:

// 唯一的全域性變數MYAPP:
var MYAPP = {};

// 其他變數:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// 其他函式:
MYAPP.foo = function () {
    return 'foo';
};
方法

在一個方法內部,this是一個特殊變數,它始終指向當前物件,而在函式內部定義的函式,this又指向undefined了!(在非strict模式下,它重新指向全域性物件window!)

apply

要指定函式的this指向哪個物件,可以用函式本身的apply方法,它接收兩個引數,第一個引數就是需要繫結的this變數,第二個引數是Array,表示函式本身的引數
另一個與apply()類似的方法是call(),唯一區別是:

  • apply()把引數打包成Array再傳入;
  • call()把引數按順序傳入。

也可以用此函式改變函式的行為

var count = 0;
var oldParseInt = parseInt; // 儲存原函式

window.parseInt = function () {
    count += 1;
    return oldParseInt.apply(null, arguments); // 呼叫原函式
};

// 測試:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
高階函式

JavaScript的函式其實都指向某個變數,函式的引數能接收變數,那麼一個函式就可以接收另一個函式作為引數,這種函式就稱之為高階函式

map&reduce

傳入一個函式引數, 作用於陣列中的每一個元素
Array.map(parameter)

5363693-637954e046f761c1

function pow(x) {
    return x * x;
}

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]

傳入一個函式引數, 作用於每一個元素和上一個元素的函式值
Array.reduce(parameter)

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
f(x) = g(f(x-1), x);

筆記會繼續更新,感謝關注

參考資料
廖雪峰_JavaScript教程