你可能遺漏的JS知識點(一)

前言

本文把平時的一些讀書筆記和理解進行了整理概括,包含一些易混淆、遺漏的知識點,也會配上一些例子,可能不是很完整,還會有點雜,但也許會有你須要的(目前先整理了一部分,筆記有點多,後續會持續更新)。git

1、變量

1.1 變量聲明

1.變量是常見的標識符,以字母、$、_開頭,可是不能包含+ - *等標識符,中文也是合法的標識符,保留字不能做爲標識符。github

2.函數聲明和賦值會分爲兩個階段,一個是編譯階段的任務,就是編譯器聲明變量,另外一個是執行階段的任務,就是js引擎去查詢賦值,因此聲明都會在代碼被執行前首先進行處理。正則表達式

3.若是在函數中使用var定義一個變量,函數調用時至關於建立了這個變量並賦值,在函數退出後就會被銷燬,因此在函數外面讀不到這個變量。可是若是在函數內定義變量時不使用var,至關因而全局變量,外面通常是讀獲得的,可是若是不運行這個函數時,至關於沒有建立這個變量,外面也是讀不到的:json

function test(){
    message = 'hello'
}
test();   // 若是不先運行這個,則讀不到message變量
alert(message);
複製代碼

4.var聲明的變量不能用delete刪除 ,delete能夠刪除一個對象的屬性,但不能刪除繼承的屬性。數組

5.變量沒有類型,變量的值纔有類型。安全

1.2 變量提高

1.提高是指聲明會被視爲存在於其所出現的做用域的整個範圍內,就是說在哪一個做用域聲明的,它就在這個做用域內(let, const並不會提高)。閉包

2.函數聲明提高:app

foo();    // typeError 至關於對undefined進行函數執行,因此是類型錯誤
bar();   // referenceError 不存在這個函數,因此是引用錯誤
var foo = function bar() {}   // 函數表達式不會提高
複製代碼

3.函數提高的優先級大於變量提高的優先級,我的理解爲函數聲明在變量之下,然後會把變量覆蓋,進而優先級更高函數

// 例一:
var fo;
fo = function(){
    console.log(456);
}
function fo(){
    console.log(123);
}
fo(); // 456 函數聲明被提高到了最上面,而後被後面的函數覆蓋


// 例二:
fo = function(){
    console.log(456);
}
fo();   // 456 同理,函數也是被覆蓋
var fo;
function fo(){
    console.log(123);
}


// 例三:
var fo = function(){
    console.log(456);
}
function fo(){
    console.log(123);
}
fo();   // 456 同理,函數也是被覆蓋


// 同時函數聲明還能被後面的聲明覆蓋,說明越後面的函數聲明排在越後面,而後把前面的函數覆蓋了:
foo();  // 3
function foo() {
    console.log(1);
}
var foo = function() {
    console.log(2);
}
function foo() {
    console.log(3);
}
複製代碼

4.繼續例子post

console.log(foo);  // 打印出函數源碼
foo();             //能夠執行 undefined 和 12
var foo=10;
foo();             //foo已經被賦值爲一個變量,沒法執行foo爲函數,因此報錯
console.log(foo);  // 上面報錯,這裏執行不到
function foo(){
    var a;
    console.log(a);
    a=12;
    console.log(a);
}
console.log(foo);

//以上實際執行順序:
var foo;
function foo(){
    var a;
    console.log(a);
    a=12;
    console.log(a);
}
console.log(foo); // 打印函數源碼
foo();      // 執行函數
foo=10;     // foo被賦值爲10
foo();      //因爲這裏報錯,foo已經被賦值,找不到這個函數,下面的都不會被執行
console.log(foo);
console.log(foo);
複製代碼

1.3做用域

1.31 全局/函數/塊做用域

1.做用域是一套規則(或者理解爲約束範圍),用於肯定在何處以及如何查找變量,其實也就是查找變量的地方。

2.每一個環境中都有一個變量對象,因此該環境下定義的變量和函數都保存在這個對象中。

3.當代碼在一個環境中執行時,會產生做用域鏈,如函數的做用域鏈的第一個對象是arguments對象(arguments在全局中是不存在的),第二個對象是上一層環境,即該環境的外部環境,以此類推,全局對象是做用域鏈中的最後一個對象。

4.if和for中用var聲明的變量都是全局變量。

5.循環變量比較:

// 例一:
for(var i = 0; i < 3; i++) {
    console.log(i);    // 0 1 2
}
console.log(i);  // 3

// 例二:
for(var i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);  // 後面再輸出三次4
    }, 0)
}
console.log(i);  // 這個先輸出,爲4

// 例三:
for(let i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);  // 1 2 3 let在每次迭代中都從新聲明
    }, 0)
}
複製代碼

6.函數參數也是屬於函數局部做用域的,它們是隱式建立的。

7.塊做用域:

  • ① with()可將代碼的做用域設置到一個特定的對象中。
  • ② try/catch中catch也會建立塊做用域,err只能在該塊做用域中訪問。
  • ③ let/const。

以上方式可將變量綁定在一個塊中,造成這個變量的塊做用域。 塊做用域還利於垃圾回收,方便引擎明確哪塊做用域的變量能夠進行回收。

8.暫時性死區:

{
   typeof a;    // undefined 未聲明的反而不會報錯
   typeof b;    // referenceErroe 暫時性死區
   let b;
}
複製代碼
1.32 詞法做用域

1.詞法做用域意味着做用域是由書寫代碼時函數聲明的位置決定的。

2.eval()和with()能欺騙詞法做用域,並且還會影響性能(由於js引擎不能事先肯定變量和函數的定義位置,即不能進行詞法靜態分析)。

3.函數在哪裏調用沒有關係,變量的位置在編譯的詞法分析階段就肯定了:

var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();    // 這裏其實就是閉包,包含了該函數的詞法做用域
} 
bar();  // 1


// 函數調用位置更換:
bar();  // undefined 全局value雖然聲明瞭,可是在bar函數調用的後面才進行賦值,因此是undefined
var value = 1;
function foo() {
    console.log(value);   
}   
function bar() {
    var value = 2;   
    foo();     
}
複製代碼
1.33 閉包

1.可參考我寫的這篇博客:[閉包]該如何理解?

1.4 條件語句

1.switch語句可判斷值、字符串、表達式等,且是全等比較,不會產生類型轉換(實際上是===不容許進行類型轉換)。

2.其實沒有else if這個規範,其實真正是:

else{     // 省略了{}這個塊而已
   if () {
   } else {
   }
}
複製代碼

3.switch:

// 例一:
switch(a){
    case 1:   // case不能放邏輯表達式,只能是常量表達式,即只能進行單一的===對比
        // code
    break;
    case 2:
        // code
    break;
    default:
        // code
}

// 例二:
var b = '42';
switch(true){
    case b == 2:   // 要進行類型轉換比較則採起這種方式
        // code
    break;
    case b == 42:
        // code
    break;
    case b > 30:    // 大小比較
        // code
    break;
    default:
        // code
}

// 例三:
var c = '42';
switch(c){
    case 1:   
    case 2:
    default:
        console.log('default') 
    case 3:
    console.log('3');
    break;
    case 4:
    console.log('4')
}
// 會獲得'default' '3', 首先會遍歷全部的case,而後沒有符合的case,而後執行default,以後沒遇到break就繼續往下執行case 3,最後到break中止。
複製代碼

1.5循環遍歷

1.for循環中先把範圍值保存爲變量,優化循環。

2.do while

do {
  // code
} while ('條件');  // 記得加上後面的分號
複製代碼

3.遍歷對比:

自身:

  • ① Object.keys返回對象自身的可枚舉屬性(數組)。
  • ② Object.getOwnPropertyNames返回對象自身可枚舉和不可枚舉屬性(數組),如數組的length屬性。
  • ③ hasOwnPropery()遍歷自身可枚舉和不可枚舉屬性。

自身和原型:

  • ① in操做符能訪問自身和原型上的可枚舉和不可枚舉屬性。
  • ② for in 能訪問自身和原型上的可枚舉屬性,不含不可枚舉屬性。

4.循環更改格式:[ [ {}, {} ,{} ], [ {}, {} ,{} ], [ {}, {} ,{} ] ] 若是要轉爲[ [ ], [ ], [ ] ] 或者其餘格式,可先用concat()方法把數組中的數組先循序鏈接起來,而後再用其餘方法處理。

5.可使用while來判斷循環,直到不知足條件後才中止判斷運行,比for循環直觀方便,如:

while( i<5 ) {  // i爲大小不肯定值
// code
i++;
}
複製代碼

6.中斷循環:forEach不能中斷,for能夠。

7.break和continue:break能跳出循環,但也只能跳出一層循環,若是須要跳出多層循環,則須要使用標籤;continue能跳過本輪循環,繼續下輪循環:

top:
  for (var i = 0; i < 3; i++){
    for (var j = 0; j < 3; j++){
      if (i === 1 && j === 1) break top;
      console.log('i=' + i + ', j=' + j);
    }
  }
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0 
// 標籤至關於定位符,用於跳轉到程序的任意位置,語式以下:
label:
複製代碼

2、數據類型

2.1數據類型

1.基本類型:number 、string、boolean、null、undefined、symbol。 引用類型:object (包含子類型function、array)。

typeof function a(){};  // 'function'
複製代碼

2.typeof 檢測能獲得的類型:

  • ①"undefined" —— 若是這個值沒有定義
  • ②"boolean" —— 若是這個值是布爾值
  • ③"object" —— 若是這個值是對象或者null
  • ④"string" —— 若是這個字是字符串
  • ⑤"number" —— 若是這個值是數字
  • ⑥"function" —— 若是這個值是函數
  • ⑦"symbol" —— ES6引入的一種新的原始數據類型Symbol,表示獨一無二的值

2.2 Number

1.JavaScript 語言的底層根本沒有整數,全部數字都是小數(64位浮點數)。

2.在JavaScript內部,整數和浮點數是一樣的儲存方法,因此3和3.0被視爲同一個值:

3.0 === 3;   // true
複製代碼

3.數字的二進制浮點數沒那麼精確:

0.1 + 0.2 === 0.3;   // false 
複製代碼

4.數字範圍:2的1024次方到2的-1023次方。

5.最大的安全整數:2^53。

6.parseInt方法用於將字符串轉爲整數。若是parseInt的參數不是字符串,則會先轉爲字符串再轉換。字符串轉爲整數的時候,是一個個字符依次轉換,若是遇到不能轉爲數字的字符,就再也不進行下去,返回已經轉好的部分。而isNaN是先將總體參數轉化爲number再進行判斷:

parseInt('abc');   // NaN
parseInt('.3');    // NaN
parseInt('');      // NaN
parseInt('+');     // NaN
parseInt('+1');    // 1
parseInt('1000', 2);  // 8 可接受第二個進制參數
複製代碼

7.toFixed注意事項:

typeof 12.236.toFixed(2);   // 'string' 指定保留位數後數字變成了字符串

42.toFixed(3);  // 會報錯,由於會把小數點算爲42的一部分,須要用使用如下方式:

(42).toFixed(3);
42.0.toFixed(3)
42..toFixed(3)
複製代碼

8.判斷是否爲整數:

// 方式一:
typeof a === 'number' && num%1 === 0

// 方式二:
Number.isInteger(a);

// 方式三:
Number.isSafeInteger(a);
複製代碼

9.NaN:

NaN === NaN    // false
NaN !== NaN    // true
Boolean(NaN)   // false
typeof NaN     // 'number'

// 判斷是否爲NaN:
// 原生方式:
Number.isNaN(n);

// 自定義方式:
function isNaN(n) {
   return n !== n;
}
複製代碼

2.3 String

1.字符串可以使用方括號[ ]來獲取該位置上的字符,也可查詢長度,但沒法像數組同樣增長或刪除字符。

2.數字字符串轉數字的一種方式:字符串與1想乘:typeof ('2' * 1) 或者typeof (+'2')

3.數字轉字符串的一種方式:數字加空字符串: typeof (1 + '')

4.拆分:

'a b c'.split(' ');  
// ['a', 'b', '', '', 'c'] b和c之間有三個空格,因此三個空格會獲得夾着的兩個空格。
複製代碼

5.字符串沒有map()、join()等方法,但能夠經過Array.prototype.call()來借用,reverse()不可借用,可先轉爲數組再使用。

6.截取:

  • ①substring() : 參數若是是負數,會變爲0,若是第一個參數大於第二個參數,則會調換位置。

  • ②substr(): 第一個參數是開始位置,第二個是長度,若是第一個參數是負數,則表示倒數計算的字符位置,若是第二個參數是負數,則返回空字符串(至關於返回長度爲0)。

  • ③match(): 用於肯定原字符串是否匹配某個子字符串,返回一個數組,成員爲匹配的第一個字符串。若是沒有找到匹配,則返回null。

  • ④search(): search方法的用法基本等同於match,可是返回值爲匹配的第一個位置。若是沒有找到匹配,則返回-1。

2.4 Boolean

1.六個false值:「」,null, undefined, 0, NaN,false。

2."''"不是空字符串,是true。

3.document.all是ie中的假值對象,是false。

2.5 Null和Undefined

1.null和undefined的名稱既是類型也是值,null指空值,曾賦過值,但目前爲沒有值,undefined指沒有值,未賦值。

2.null是js中的一個bug,由於不一樣的對象在底層都表示爲二進制,在js中二進制前三位都爲0時就判斷爲object類型,而null的二進制表示是全0,因此執行typeof時會獲得‘object’(或者把null當成一個空對象指針,因此typeof檢測會獲得object)。

3.null==undefined 是true,且不進行類型轉換,由於它們是相似的值,且只有null和undefined是==,和其它對比都是false,因此:

null == 0          // false
undefined == 0     // false
null == ''         // false
undefined == ''    // false

null == fasle         // false
undefined == false    // fasle

// 只有自身轉化纔會是布爾值:
!null == true         // true
!undefined == true    // true

// 但運算時,null會轉型爲0,undefined轉爲NaN:
null + 3  // 3
undefined + 3  // NaN

// 判斷類型:
typeof null      // 'object'
typeof undefined // 'undefined'
複製代碼

2.6 廣義Object

2.6.1 狹義對象

1.全部的對象都是繼承自Object的,都會帶有這些屬性,toString(), valueOf(), constructor。

2.建立對象 :

// ①字面量方式:
var o = {};

// ②Object.create方式:
Object.create('這個對象的原型,對象屬性的描述')
Object.create({x:1,y:2}) // 繼承了這個對象的屬性
Object.create(null)      // 則不會繼承任何屬性和方法;
Object.create(Object.prototype) // 和new Object()同樣建立了一個空對象

// ③構造函數方式:
function createPerson (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function () {
        alert(this.name);
    }
}

// ④工廠模式方式:
function createPerson (name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function () {
        alert(this.name);
}
    return o;
}
複製代碼

構造函數與工廠模式區別:

  • ①沒有顯示的建立對象。
  • ②直接將屬性和方法賦予給了this對象。
  • ③沒有return語句。

構造函數過程:

  • ①建立一個空對象。
  • ②將構造函數的做用域賦給空對象(this指向空對象,空對象原型指向構造函數原型)。
  • ③執行代碼(爲這個空對象添加屬性)。
  • ④返回新對象(return this)。

構造函數之因此叫「構造函數」,就是說這個函數的目的,就是操做一個空對象(即this對象),將其「構造」爲須要的樣子。構造函數中若是有return一個對象,則new這個構造函數時獲得的是這個對象,而不是新的this對象(能夠認爲構造函數內開頭先定義了一個this變量,而後最後返回this)。

構造函數內的方法在每次生成實例的時候,實例對象內的函數都是新生成的,至關於new了一個函數,由於函數也是對象,因此每次生成實例對象內的函數的時候,就至關於定義了一個對象,因此雖然它們名字相同,但倒是不一樣的函數。

// o指對象,返回的就是對象自己
o.valueOf() === o  // true 

// 數組也是如此,由於數組也是對象,也能夠用構造器生成:
var a = new Array()
// 就像構造函數建立對象,因此a也會帶有toString等屬性,由於對象都會繼承toString等方法。
複製代碼

4.訪問對象屬性:若是對象的屬性是動態、不可預測或不符合變量規範的,用方括號的形式person["name"],而不能用點.方式,方括號內要放字符串,但當name是變量時,也能夠用person[name]來訪問屬性。

5.檢測屬性:

  • in // 檢測屬性是否存在於自身或原型上,含不可枚舉屬性
  • hasOwnProperty() // 檢測屬性是否存在於自身,含不可枚舉屬性
  • propertyIsEnumerable() // 檢測屬性是否可枚舉

6.對象轉換:

// ①Object()可將任何值轉爲對象;Object()返回一個空對象;若是Object方法的參數是一個對象,它老是返回該對象:
var value = {};
var obj = Object(value) // 返回原對象
obj === value  // true

// ②valueOf返回一個對象的「值」,默認狀況下返回對象自己:
var obj = new Object();
obj.valueOf() === obj  // true

// ③new Object(value)的值是value對象。
複製代碼
var o1 = new Object();
o1.toString() // "[object Object]" 注意大小寫
複製代碼

數組、字符串、函數、Date 對象都分別部署了自定義的toString方法,覆蓋了原生的Object.prototype.toString方法,原生的Object.prototype.toString()返回的是類:

// 數組:
[1, 2, 3].toString();  // "1,2,3"

// 字符串:
'123'.toString();  // "123"

// 函數:
(function () { return 123;}).toString();   // "function () { return 123; }"

// Date:
(new Date()).toString();  // "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
複製代碼

8.對象是引用同一個地址:

var o1 = {};
var o2 = o1;
o1 = 1;  // o1是改變了本身的指向,而不是改變{}
o2;      // {} o2已指向{}的地址,只要這個地址的對象沒有變,它就不會變
複製代碼

原始類型是值拷貝:

var x = 1;
var y = x;
x = 2;
y   // 1
複製代碼

深拷貝:

// 方式一:
function deepCopy(obj) {
        return JSON.parse(JSON.stringify(obj));
}

// 方式二:
function deepCopy (p, c) {
            c = c || {};
            for (let i in p) {
                if (p.hasOwnProperty[i]) {   // 排除繼承屬性
                    if (typeof p[i] === 'object') {
                        c[i] = Array.isArray(p[i]) ? [] : {};
                        deepCopy[p[i], c[i]];
                    } else {
                        c[i] = p[i];
                    }
                }
            }
            return c;
        }
複製代碼

9.對象屬性描述符:

// configurable 可否修改屬性
// enumerable 是否可枚舉
// writable 可否修改屬性的值
// value 屬性的數據值

var myObject = { a: '2' };
var b = Object.getOwnPropertyDescriptor(myObject, 'a');
console.log(b);   // {value: "2", writable: true, enumerable: true, configurable: true}

Object.defineProperty(myObject, 'a', {
            value: '3',   
            writable: true,       // 可修改
            enumerable: true,   // 可枚舉
            configurable: true   // 可配置,若是爲false,則不能修改以上配置,但能夠//myObject.a= 5, writable能夠變爲false, 但不能變爲true
})
複製代碼

10.get set

var other = {
    get a(){
        return this._a_;
    },
    set a(val){
        this._a_ = val*2;
    }
}

console.log(other);    // {}
console.log(other.a);  // undefined
other.a = 2;
console.log(other.a);  // 4
複製代碼

11.Function.prototype是一個函數,RegExp.prototype是一個正則表達式,Array.prototype是一個數組,它們都是空的,(但總的來講它們都是對象)。

12.字符串要訪問屬性或方法時,js會自動將其轉化包裝對象,這種讓js自行執行,而不要人爲轉爲包裝對象,不然會影響性能。

'abc'.length  // 3 
複製代碼
2.6.2 函數

1.函數中執行return語句後馬上退出,因此放在return語句後面的語句不會執行;未指定返回值的函數返回的是undefined。

2.函數的參數在內部是用數組來表示的,arguments是類數組,可用arguments[0]來獲取參數,arguments的長度是由傳入的參數個數決定的,而不是由命名參數的個數決定的;參數傳遞的都是值,傳入引用類型值時注意是否有影響。

3.函數名稱和參數長度:a.name , a.length是預期傳入的參數個數,不是實際參數個數。

4.沒有函數簽名,因此沒有重載,即同名函數會被後面發覆蓋,可是能經過判斷參數的類型和數量來做出不一樣的反應來模仿方法的重載。

5.函數其實是對象,每一個函數都是Function類型的實例,並且和其餘應用類型同樣具備屬性和方法,如call、apply、length、contructor、prototype、name等屬性,函數名其實是指向函數對象的指針。

6.區分函數聲明和表達式的方法是看function出如今聲明的哪一個位置,若是function是第一個詞,就是函數聲明,不然爲函數表達式(自執行函數是以括號開頭,因此爲表達式)。

7.函數內有兩個特殊的對象:

  • ①arguments: arguments有一個callee屬性,是一個指針,指向擁有這個arguments對象的函數。

  • ② this: this引用的是函數據以執行的環境對象。

8.一些區別:

  • ①函數聲明:function a() {}可直接a()調用,花括號後面不用分號結尾。

  • ②函數表達式:let t = function() {} 可用t()調用,且通常不帶函數名,若是加上函數名,該函數名只在函數體內部有效,在函數體外部無效,花括號後面帶分號:

var print = function x(){
    console.log(typeof x);
}
x;         // ReferenceError: x is not defined
print();   // function
複製代碼
  • ③構造函數:
var add = new Function(
   'x',
   'y',
   'return x + y'
)
// 等同於
function add(x, y) {
   return x + y;
}
複製代碼
  • ④函數執行時所在的做用域,是定義時的做用域,即詞法做用域,而不是調用時所在的做用域:
var a = 1;
var x = function () {
    console.log(a);
}

function f() {
    var a = 2;
    x();
}

f();   // 1
複製代碼

9.原生函數:

  • Number(), String(), Boolean(),
  • Object(), Array(), Function(),
  • RegExp(), Date(), Error(), Symbol()

10.類型判斷:

var a = new String('abc');
typeof a;   // 'object' a爲包裝對象
a instanceof String  // true
Object.prototype.toString(a);   // '[object, Object]' 若是不使用call,不論傳入什麼,都爲Object類,這個沒什麼用,若是要用於判斷類型,都得加call
Object.prototype.toString.call(a);   // '[object, String]' 讓a調用Object上的toString方法,屬於String類
複製代碼

11.返回

return (  // return若是有換行,須要加括號
    a*2;   
  )       
複製代碼

12.若是構造函數內部有return語句,並且return後面跟着一個對象,new命令會返回return語句指定的對象;不然,就會無論return語句,返回this對象:

// 例一:
var Vehicle = function (){
    this.price = 1000;
    return { price: 2000 };
}
(new Vehicle()).price;  // 2000 若是不使用new,則this將變爲全局的


// 例二:若是對普通函數使用new命令,則會返回一個空對象:
function getMessage() {
    return 'this is a message';
}
var msg = new getMessage();
msg    // {}
typeof msg  // "object"
複製代碼
2.6.3 數組

1.可經過設置數組的長度對數組進行增長或刪減元素,也能夠爲數組添加字符串鍵,但不會算入數組長度(數字字符串除外),如:a['13'] = 'test'

2.檢測是否爲數組的兩種方法:

  • ①value instanceof Array
  • ②Array.isArray(value)

3.對數組調用toString()方法時返回每一個值的字符串以逗號鏈接起來的字符串,alert()接受的是字符串參數,因此:

var people=['per1', 'per2'];
alert(people.valueOf());
// 返回的仍是以逗號鏈接的字符串,由於會默認調用後臺的toString()方法將people轉爲字符串
複製代碼

4.value.join("|"),不傳參時默認以逗號鏈接。

5.返回值:

  • push()、unshift()返回的是修改後的數組的長度
  • pop()、shift()返回的是刪除的項

6.sort()是高階函數,可傳入方法:

var arr = [2, 10, 20, 1];
arr.sort(function (x, y) {   // 升序
    if (x < y) {
        return -1; 
    }
    if (x > y) {
        return 1; 
    }
    return 0;
});
console.log(arr);    // [1, 2, 10, 20]

//或者
function(x, y){
     return x - y;  // 升序
   } 
複製代碼

7.棧與隊列:

  • 棧方法:LIFO(last-in-first-out)後進先出push()和pop()。
  • 隊列方法:FIFO(first-in-first-out)先進先出push()和shift()。

8.數組原始值是否改變:

不改變原數組:(鏈接\截取\循環)

  • concat:鏈接多個數組,返回新的數組
  • join:將數組中全部元素以參數做爲分隔符放入一個字符
  • slice:slice(start,end),返回選定元素
  • map,filter,forEach,some,every等不改變原數組

改變原數組:(增長\刪除\換序)

  • shift:將第一個元素刪除而且返回刪除元素,空即爲undefined。
  • unshift:向數組開頭添加元素,並返回新的長度。
  • pop:刪除最後一個並返回刪除的元素。
  • push:向數組末尾添加元素,並返回新的長度。
  • reverse:顛倒數組順序。
  • sort:對數組排序。(數組排序後和與排序前的數組絕對相等===,由於仍是同一個引用)
  • splice: splice(start,length,item)刪,增,替換數組元素,返回被刪除數組,無刪除則不返回,若是隻提供第一個參數,等同於將原數組在指定位置拆分紅兩個數組:
var a = [1, 2, 3, 4];
a.splice(2);   // [3, 4]
a;             // [1, 2]
複製代碼

9.delete刪除數組元素,不會改變數組長度,該位置會變空爲undefined。

10.類數組轉數組:由於slice內部返回的是新建的數組(使用循環取值):

Array.prototype.slice.call({ 0: 'a', 1: 'b', length: 2 })  // ['a', 'b']
Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);
複製代碼

11.reduce():

  • 一參:累積變量,默認爲數組的第一個成員
  • 二參:當前變量,默認爲數組的第二個成員
  • 三參:當前位置(從0開始)
  • 四參:原數組

應用:找出最長字符串:

function findLongest(entries) {
    return entries.reduce(function (longest, entry) {
        return entry.length > longest.length ? entry : longest;
  }, '');
}
findLongest(['aaa', 'bb', 'c']);  // "aaa"
複製代碼

12.數組去重:

let s = new Set([1, 2, 3, 3, '3']);
s;   // Set {1, 2, 3, "3"}
let arr = [..s];

let arrs = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];
arrs.filter(function (element, index, self) {
    return self.indexOf(element) === index;
})
複製代碼

13.空單元數組:

// 例一:
var arr = ["a", "b", "c"];
console.log(arr['2']);     // 'c'
arr['5'] = 'e';
console.log(arr.length);   // 6
console.log(arr);   // ["a", "b", "c", empty × 2, "e"]


// 例二:
var a = new Array(3);
console.log(a);     // [empty × 3] 空單元數組
var b = [undefined,undefined,undefined];  // 這個不是空單元數組,是值爲undefined的數組


// 例三:
var c = [];
c.length = 3;
console.log(c);   // [empty × 3] 空單元數組
複製代碼

14.數組和字符串都有的方法:splice()、indexOf()、lastIndexOf()、contact()

2.7 類型轉換

1.toString()轉換爲字符串,若是是數字,可傳遞基數來確認返回的是多少進制的數字字符串:

let num = 12;
num.toString(8)  // 返回8進制字符串
複製代碼

2.alert會調用對象的toString()方法,alert(a)alert(a.toString())是同樣的。

3.對象轉化:

  • ①對象轉數字默認先調用valueOf()方法,若是返回的不是原始值,則再調用toString()方法。

  • ②對象轉字符串默認先調用toString()方法,若是返回的不是原始值,則再調用valueOf()方法。

  • ③日期對象轉數字時會默認直接調用toString()方法。

4.null和undefined沒有toString()方法,可是可使用String()來將它們轉爲字符串。

5.Number轉化:

Number({});         // NaN
Number({a: 1});     // NaN

Number([1, 2, 3]);  // NaN
Number([]);         // 0
Number([5]);        // 5

String([]);         // ""
複製代碼

6.使用:

var a;
typeof a;   // undefined
typeof b;   // undefined 儘管沒聲明b,但不報錯,但若是使用b,則會報錯

var c = {};
c.a  // undefined 訪問不存在的對象屬性不會報錯,因此也不能根據c.a===undefined來判斷是否有a屬性。
複製代碼

7.數組的toString方法(即Array.prototype.toString())被從新定義過,將全部單元字符串後用逗號鏈接起來,而原生的Object.prototype.toString()返回的是「類」。

var a = [1, 2, 3];
Object.prototype.toString(a);    // "[object Object]" 返回「類」
console.log(a.toString());       // '1,2,3' 會先找到Array上的toString方法
console.log(Array.prototype.toString.call(a));   // '1,2,3' 讓a調用Array上的toString方法
console.log(Object.prototype.toString.call(a));  // [object Array] 讓a調用Object上的toString方法
複製代碼

8.JSON.stringify()能夠將對象轉化爲字符串,但它本質上是若是對象中有toJSON方法就先調用toJSON方法將所要轉化的對象換爲安全的JSON值,把循環引用類型、函數、null、undefined等不符合json的值過濾掉,而後再交由toString方法來轉化。

JSON.stringify()還可接受數組參數或函數參數,做用和toJSON相似,用於過濾對象:

var a = {
    b: 42,
    c: '36',
    d: [1,2,3]
};
JSON.sringify(a, ["b", "c"]);  // "{"b":42, "c":"36"}"保留傳入數組中包含的對象屬性
JSON.stringify(a, function(k, v) {
    if (k !== "c"){
        return v;
    } 
})    // "{"b":42, "d":[1,2,3]}"
複製代碼

9.parseInt:

parseInt(new String(42))   // 42 是數字 
複製代碼

由於parseInt是針對字符串的,所要parseInt會先調用所傳入參數的toString方法將參數轉化爲字符串,而後再解析數字。

10.在存在布爾值中使用==或===進行比較,或數字與字符串比較時,都是先將不是數字的那方先轉換爲數字(轉爲數字的優先級:布爾值>對象>字符串>數字),而後再進行比較:

var a = '123';
var b = true;
a == b;   // false 

//由於123不等於1,會先將布爾值轉爲1,而後和'123'比較,而後將'123'轉爲123再進行最後比較,因此「存在」和「==true」是不同的,好比:

var a = '42';
// if(a) 和 if(a==true) 不同。
複製代碼

11.進行算數運算時,優先調用valueOf()方法來轉化數字,若是未轉化成原始類型,則再調用toString()方法,可是Data對象是優先調用toString()方法。

最後

由於比較多,因此目前只整理到這裏,後續有些比較重要難懂的模塊會分開更新,但願對你有所幫助,若有不合理的地方歡迎指正,喜歡的話歡迎關注一波,後續會持續更新。

GitHub傳送門
博客園傳送門

相關文章
相關標籤/搜索