JavaScript基礎入門筆記

0 介紹

0.1 ECMAScript

ECMA-262 的第 5 版是 JS 的第一個穩定版本,獲得了各瀏覽器廠商的支持。
javascript

  • 語法
  • 類型
  • 語句
  • 關鍵詞
  • 保留字
  • 操做符
  • 對象

0.2 DOM

文檔對象模型是針對 XML 但通過擴展用於 HTML 的 API 。DOM 把整個頁面映射爲一個多層次節點結構。HTML 或 XML 頁面中的每一個組成部分都是某種類型的節點,這些節點又包含着不一樣類型的數據。
document object model 文檔對象模型,裏面提供了一些屬性和方法,可讓咱們操做頁面的元素css

0.3 BOM

原則上講,BOM只處理瀏覽器窗口和框架,但下面一些針對瀏覽器的 JS 擴展也被看作是BOM的一部分。
browser object model 瀏覽器對象模型,裏面提供了一些屬性和方法,可讓咱們操做瀏覽器。html

1 導入JS

1.1 三種常見導入

1.1.1 行內導入JS(慎重:不安全)

<div onclick="alert('hello world')"></div>
複製代碼

1.1.2 內嵌式

<script> alert('hello world') </script>
複製代碼

1.1.3 外鏈式

// 新建一個js文件
<script src="./js/demo.js"></script>

// or

<script src="./js/demo.js" type="text/javascript"></script>
複製代碼

1.2 內嵌與外鏈不能同時操做

內嵌導入和外鏈導入不能合併在一塊兒,若是當前是外鏈導入的,那麼在script腳本塊找那個編寫的全部代碼都不會被執行。java

<script src="./js/demo.js">
  alert('hello world')
</script>
複製代碼

1.3 位置編寫位置

咱們通常性會把css放在body的上面,把js放在body末尾(約定速成的規範)node

可是若是放在了標籤前面那麼將如何處理?面試

頁面加載完全部資源以後執行操做編程

在js中json

window.onload=function(){

}

複製代碼

在jq中後端

$(document).ready(function(){

})

window.addEventListener('load',function(){},false);

// ie8如下

window.attachEvent('onreadystatechange',function(){
})
複製代碼

2 JS經常使用的輸出方式

2.1.彈窗輸出

2.1.1 alert

  • 在瀏覽器中彈出一個提示框(提供肯定按鈕,點擊肯定彈窗消失)
  • 使用alert彈窗信息,提示的內容最後都會轉換成字符串(調用了toSring這個方法)
alert(1)
alert({name:'wjw'}) //=> '[object Object]'
alert([13,14]) //=> '12,13'
複製代碼

2.1.2 confirm

  • 在alert基礎上增長了讓用戶選擇的操做(提供兩個按鈕:肯定和取消)
  • 當用戶點擊肯定按鈕的時候,咱們接收到的結果是true,點擊是取消按鈕咱們接受到的結果是false,此後咱們能夠根據結果來處理便可
var wjw = confirm("are you sure");
alert(wjw);
複製代碼

2.1.3 prompt

    • 在confirm 基礎上增長讓用戶增長輸入的效果
    • 用戶點擊取消按鈕,咱們獲取到的結果是null,若是用戶點擊是肯定按鈕,咱們將獲取用戶輸入的信息
    • 在真實的項目中,通常性會使用二次封裝的彈窗,不會使用這種彈窗
var flag = prompt("are you sure");

alert(flag)
複製代碼

2.2 控制檯輸出

控制檯輸出,方便開發調試數組

2.2.1 console

  • 在控制檯輸出,優點不會轉換數據類型,輸出什麼格式的數據均可以
console.log({name:'wjw'});

console.dir() //比log輸出更加詳細一些
console.table //把json數據展現成一個表格
複製代碼

3 JS定義值

語法 ECMAScript 的語法大量借鑑了 C 及其餘類 C 語言(如 Perl 和 Java)的語法。 區分大小寫

3.1 註釋

// 單行註釋

/* * 這是一個多行 * (塊級)註釋 */
複製代碼

3.2 嚴格模式

嚴格模式 ES5 引入了嚴格模式的概念,在嚴格模式下,ES3 中的一些不肯定行爲將獲得處理,並且隊某些不安全的操做也會拋出錯誤。要在整個腳本中啓用嚴格模式,能夠在頂部添加以下代碼:
這行代碼看起來像是字符串,並且也沒有賦值給任何變量,但其實它是一個編譯指 示(pragma),用於告訴支持的JavaScript引擎切換到嚴格模式。在函數內部的上方包含這條編譯指示,也能夠指定函數在嚴格模式下執行:

function doSomething(){
 "use strict";  //函數體
}
複製代碼

3.3 變量、常量

變量是能夠變得 常量是不可變的

3.3.1變量

  • 變量其實只是一個無心義的名字,它所表明的意義都是其存儲的那個值
  • 讓原有的num變量存儲的值修改成13(變量只能表明一值)

js定義變量的方法

// var 變量名 = 值;

var num = 12;
var name = 'wjw'
複製代碼

3.3.1常量

  • 任何一個具體的數據都是常量,例如12是個常量
  • 和變量累死,咱們設置一個常量(也就是一個名字),給其存儲一個值,可是這個存儲的值不能修改
const num = 12;
複製代碼

3.4 JS中命名規範

  • JS中嚴格區分大小寫
var test = 'wjw';
var Test = 'wjh';
console.log(test);
// 輸出test
複製代碼
  • 遵循國際命名規則"駝峯命名法"

第一個單詞首字母小寫,其他每個有意義單詞首字母大寫

var studentInfo; // 學生信息
// 所見即所得
// 例子:

/* * info : information 信息 * init : initlization 初始化 * add/insert/create 增長插入建立 * remove/rm/clear/del/delete 刪除 * update 修改 * get/query/select : 查詢獲取 */
複製代碼
  • 命名的時候可使用$、_、數字、字母,可是數字不能做爲名字的第一位
var student_info;
var $xxx; //=> 通常都是應用jq得到到的值
var _xxx; //=> 通常這樣的狀況表明變量是一個局或者公共的變量
複製代碼
  • JS中不少字都是有特殊含義的,咱們這些詞,叫作關鍵詞;如今沒有特殊含義,之後可能會做爲關鍵的,咱們叫作保留字;二關鍵詞和保留字不能夠隨便用來命名;

image.png

image.png

4 JS數據類型

4.1 數據類型

4.1.1 基本數據類型(值類型)

  • Number  數字
  • String  字符串
    • 單引號包裹起來的都是字符串(單雙號沒有區別)
  • Boolean  布爾
    • true false => 布爾值只有兩個值
  • null 空對象指針
  • undefined  未定義

4.1.2 引用數據類型

  • {}  普通對象
  • []  數組
  • /^$/ 正則
  • ...

4.1.3 function數據類型

  • funciotn fn (){}

4.2 數據類型檢查

  • typeof
    • 用來檢測數據類型的運算符
  • instanceod
    • 檢測某個實例是否屬於這個類
  • constructor
    • 獲取當前實例的構造器
  • Object prototype.toSting.call()
    • 獲取當前實例的所屬類信息

4.2.1 typeof

操做符 typeof 是用來檢測給定變量的數據類型的操做符。對一個值使用 typeof 操做符可能返回下列某個字符串:

"undefined"
"boolean"
"string"
"number"
"object" // 若是這個值是對象或者null "function"
複製代碼

4.3 布爾值

Boolean()

  • 把其餘數據類型的值轉化爲布爾類型
  • 只有0、Nan、null、undefined這五個數據值轉換爲布爾類型的false,其他的都會變成true

image.png

歎號在JS中海油一個做用:取反,先把值轉換爲布爾類型,而後再去取反

image.png

!!

在歎號取反的基礎上取反,取反兩次至關於沒有操做,可是卻已經其餘類型值轉化爲布爾類型了,和Boolean是相同的效果

4.4 字符串

在JS中單引號和雙引號包起來的都是字符串

12 - > number
'12' -> string
'[12,23]' -> string
複製代碼

4.4.1 toString()

第一種是使用幾乎每一個值都有的 toString()方法。多數狀況下,調用 toString() 方法沒必要傳遞參數,但在調用數值的 toString()方法時,能夠傳遞一個參數:輸出數值的基數。默認狀況下,toString() 方法以十進制格式返回數值的字符串表示。而經過傳遞基數,toString() 能夠輸出二進制、八進制、十六進制等。

var num = 10;
alert(num.toString());    // "10"
alert(num.toString(2));  // "1010"
alert(num.toString(8));  // "12"
alert(num.toString(10));  // "10"
alert(num.toString(16));  // "A"
複製代碼

經常使用方法

image.png

4.5 number數字

0 12-22 12.5 js中多增長了一個number類型的數據NaN  typeof NaN -> Number

var intNum = 55; // 十進制整數 var octalNum1 = 070; // 八進制的56
var octalNum1 = 079; // 無效的八進制數值——解析爲79 
var octalNum1 = 08; // 無效的八進制數值——解析爲8 
var hexNum1 = 0xA;  // 十六進制的10
var hexNum2 = 0x1F; // 十六進制的31
複製代碼

注意,八進制字面量在嚴格模式下是無效的,會致使拋出錯誤。

4.5.1 數值範圍

ECMAScript 可以表示的最小數值保存在 Number.MIN_VALUE 中——在多數瀏覽器中,這個值是 5e-324;可以 Number.MAX_VALUE 中——在大多數瀏覽器中,這個值是1.7976931348623157e+308。若是某次計算的結果獲得了一個超過JavaScript 數值範圍的值,那麼這個數值將會自動轉換爲 Infinity 值,若是這個數值是負數,則會轉換成 -Infinity(負無窮),若是這個數值是正數,則會轉換成Infinity(正無窮)。要肯定一個數值是否是有窮的,可使用 isFinite() 函數。

4.5.2 NaN

  • not a numer : 不是一個數,可是屬於number類型
  • NaN == NaN : false , NaN 和任何其餘值都不相等

4.5.3 isNaN()

  • 用來檢測當前這個值是不是非有效數字,若是不是有效數字,檢測的結果是true , 反之是有效數字則爲false
isNaN(0)   // ->false
isNaN(NaN) // ->true
複製代碼
  • 當咱們使用isNaN檢測值的時候,檢測的值不是number類型的,瀏覽器默認的吧值先轉換爲number類型,任何再去檢測
isNaN('12') //->false
複製代碼

4.5.4 Number()

  • 把其餘數據類型值轉化成number類型的值
Number('12') // -> 12
Number('12px') // ->NaN
// 在使用Number轉換的時候只要字符串中出現任何一個非有效數字字符,最後的結果都是NaN

Number(true) //-> 1 
Number(false) //-> 0
Number(null) // -> 0
Number(undefined) //->NaN


複製代碼
  • 把引用數據類型轉換成number,首先須要吧引用數據類型轉爲字符串(toString),在把字符串轉換爲number便可
Number([]) // -> ""
Number([12]) // -> 12
Number([12,13]) // -> 12,13 (,是非有效字符) -> NaN
Number({age:12}) // ->NaN
Number({}) // -> NaN
複製代碼

4.5.5 pareInt

  • 也是吧其餘數據類型值轉換爲number,和Number方法在處理字符串的時候有所區別
Number('12px') // -> NaN
parseInt('12px') // -> 12
複製代碼
  • 提取規則:從左到右依次查找有效數字字符,知道遇到非有效數字字符爲止(無論後端是否還有,都不找了)
parseInt('12px13') // -> 12
複製代碼

4.5.6 數值轉換

處理整數最經常使用的仍是 parseInt() ,它會忽略字符前面的空格,直到找到第一個非空格字符。若是第一個字符不是數字字符或者負號,parseInt() 就會返回 NaN;也就是說,用 parseInt() 轉換空字符串會返回 NaN 。若是第一個字符是數字字符, parseInt() 會繼續解析第二個字符,直到解析完全部後續字符或者遇到了一個非數字字符。若是字符以「0x」開頭且後面跟數字字符,會被解析爲 16 進制整數;
以「0」開頭且後面跟數字字符,會被解析爲 8 進制整數。下面給出一些例子:

var num1 = parseInt("1234blue");   // 1234
var num2 = parseInt("");     // NaN
var num3 = parseInt("0xA");    // 10(十六進制)
var num4 = parseInt(22.5);   // 22
var num5 = parseInt("70");     // 70
var num6 = parseInt("0xf");    // 15(十六進制)
複製代碼

4.5.7 pareFloat

  • 在pareInt的基礎上能夠識別小數點
pareInt('12.5px') -> 12
pareFloat('12.5px') -> 12.5
複製代碼

4.6 null 和undefined

  • null : 空,沒有
  • undefined :未定義,沒有
  • "" : 空字符串,沒有
  • 0: 也能夠理解爲沒有

4.6.1 空字符串和null的區別

  • 都是去去種樹
  • 空字符串屬於去挖了個坑,可是沒有種任何東西
  • null屬於連坑都沒挖
  • 空字符串相對於null來講開闢了內存地址,消耗了那麼一丟丟的性能

4.6.2 null和undefined的區別

  • null通常都是暫時沒有,預期中之後會有的(可能之後也沒有達到預期),在js中null都是手動先賦值爲null,後期咱們在給其賦具體值
  • undefined:徹底沒有預料以內的

4.7 Object 對象

ECMAScript 中的對象其實就是一組數據和功能的集合。對象能夠經過執行 new 操做符後跟要建立的對象類型的名稱來建立。而建立 Object 類型的實例併爲其添加屬性和(或)方法,就能夠建立自定義對象,以下所示:

var o = new Object();
複製代碼

每個對象都是由零到多組 屬性名(key鍵):屬性值(value值) 組成的,或者說有多組鍵值對組成的,每一組鍵值對中間用逗號分隔

4.7.1 屬性

描述這個對象特色特徵的

var obj ={name:'wjw',age:8};
複製代碼

4.7.2 獲取

某個屬性名對應的屬性值或者數字格式的

obj.name
obj['name']
複製代碼

4.7.3 存儲

屬性值能夠是任何數據類型

  • 對象名.屬性名:忽略屬性名的單雙引號
  • 對象名[屬性名]:不能忽略單雙引號
// 若是屬性名是數字如何操做
obj.0 語法不支持
obj[0] / obj['0'] 兩種都支持
複製代碼

若是操做的屬性名在對象中不存在,獲取的結果是undefined

obj.sex // ->undefined
複製代碼

4.7.4 設置/修改

一個對象的屬性名是不能重複的(惟一性),若是以前存在就是修改屬性值的操做,反之不存在就是新的設置屬性的操做

obj.sex = '男';
obj['age'] = 9;
複製代碼

4.7.5 刪除

假刪除:讓其屬性賦值爲null,可是屬性仍是對象
obj.sex = null;
複製代碼

真刪除:把整個屬性都在對象中暴力移出
delete obj.sex
複製代碼

4.8 基本數據類型 和 引用數據類型的區別

JS是運行在瀏覽器中的(內核引擎),瀏覽器會爲JS提供賴以生存的環境(提供給js代碼執行的環境)=> 全局做用域window(global)

var a = 12;
var b = a; // 把A變量存儲的值賦值給B
b = 13;
console.log(a);

var n ={name:'wjh'};
var m = n;
m.name = 'wjw'
console.log(n.name)
複製代碼
  • 基本數據類型是按值操做的:基本數據類型的賦值的時候,是直接把值賦值給變量便可
  • 引用數據類型是按照空間地址(引用地址)來操做的: var n = {name:'wjw'}
    • 先建立一個變量n
    • 瀏覽器首先會吧開闢一個新的存儲控件(內存控件),目的是吧對象中須要存儲的內容(鍵值對)分別的存儲在這個空間中,爲了方便後期找到這個空間,瀏覽器給空間設定一個地址(16進制)
    • 把空間的地址賦值給了變量

image.png

4.9 function數據類型

函數數據類型也要按照引用地址來操做的

函數:具有必定功能的方法

// => 建立函數:
function 函數名(){
	//=> 函數體:實現某一個功能的具體JS代碼
}
// => 執行函數:至關於使用洗衣機洗衣服(若是函數只建立了,可是沒有去執行,函數沒有任何的意義)
// 函數名()
複製代碼
function fn(){
	console.log(1+1);
}
fn; // => 輸出函數自己
fn(); // => 把函數執行(吧函數體重實現功能的代碼執行)
複製代碼

image.png

形參:形式參數(變量),函數的入口
當咱們建立一個函數想要實現個功能的時候,發現有一些材料不清楚,只有當函數運行的時候,別人傳遞給我,我才知道,此時咱們就須要設定入口,讓用戶執行的時候經過入口把值把咱們

function fn(num1,num2){
	console.log(num1+num2)
}
// 實參:函數執行傳遞給函數的具體值就是實參
fn(1,2);
fn(10,20);
複製代碼

4.10 數據類型轉換

把其餘數據類型轉換爲number類型
-> isNaN、Number、pareInt、parseFloat
-> 在進行數據加減乘除數學運算的時候

// true -> 1 false->0
// ''->0  '12'->12  '12px'->NaN/12
// '小夥子'->NaN
// null -> 0 
// undefined-> NaN
{} /^$/ function() ->NaN
[]
[12]->'12'->12
['12,13']->'12,23'->NaN
// => 引用數據類型轉換爲數字
// 經過toString方法把數組轉換爲字符串,而後在調用Number轉換爲數字
複製代碼

4.10.1 JS中的數據運算

  • +、-、*、/加減乘除
  • 除了加法有特殊性,其他的運算符都是數學運算,也是遇到非數字類型,須要把其轉換爲number再運算
1-'1' -> 0
10*null -> 0
10/undefined -> NaN
10*[10]->100
複製代碼

4.10.2 加法的特殊性:

  • 在遇到字符串的時候,+不是數學運算,而是字符串拼接,只要不遇到字符串就是數學運算
1+'1' -> '11'
null+'1' -> ‘null1’

複製代碼
  • 字符串拼接:是把其它的值轉換爲字符串而後再拼接(toString)
  • 其它數據類型的toString是直接的把值用單(雙)引號包起來極客,只有對象的特殊性,對象的有特殊性,對象.toStirng==='[Object Object]

4.10.3 將其它數據類型轉換爲布爾類型

  • Boolean、!、!!
  • 在條件判斷的時候、也是轉換爲布爾類型,而後驗證條件的真假
  • 只有0、NaN、空字符串、null、undefined五個轉換爲false、其他的都是轉換爲true
[] -> true
-1 -> true

if(box){
		// => 首先把box變量存儲的值獲取到,轉化爲布爾類型,若是爲true條件成立,反之不成立
}

if(3+'3px'){
	// 條件成立: 3 + '3px' = '33px' 
}
if(3-'3px'){
	// 條件不成立: 3-'3px' = NaN
}
複製代碼

4.10.4 在使用==進行比較的時候

在使用==進行比較的時候,若是左右兩邊的數據不相同,瀏覽器默認轉換爲相同的類型,而後在比較('==='不會這樣操做)

// 對象和對象: 應用數據類型比較的空間地址不同,不是一個空間
[] == [] -> false
var a ={}
var b = a;
a==b -> true
複製代碼

4.10.5 對象和數字:吧對象轉換成數字

[]== 0 -> true
({})=== NaN -> false
NaN和本身不相等和其它任何值都不相等 
複製代碼

4.10.6 對象和字符串:把兩邊都轉換爲數字比較的

[]==='' -> true
複製代碼

4.10.7 對象和布爾值:把兩邊都轉換成數字

[]==true ->  0==1 ->false
[]==false ->  0==0 ->true
![]==false ->  ![]  ->把數組變成爲布爾在取反=false
false=false -> true
複製代碼

字符串和數字:字符串轉換爲數字
字符串和布爾:都轉爲數字
布爾和數字:布爾轉換爲數字

規律:兩個等於號比較,左右兩邊數字值的類型不同,瀏覽器會吧兩邊的類型都轉換爲數字而後再比較,可是null和undefined除外
null==undefined -> true
null===undefined -> false
null 和 undefined 和其它任何都不相等
null==0 -> false null以及undefined和其它任何值都不相等

5 JS中常見的操做的語句

5.1 if、else if 、else

判斷操做語句

if(條件1){
	//=>條件1成立執行的操做
}else if(條件2){
	//=>上面條件不成立,條件2成立,執行的操做
}
...
else{
	// => 以上條件都不成立執行的操做
}
複製代碼

若是好幾個條件都成立了,只吧第一個成立的條件執行,後面成立的條件忽略無論
條件:

A==B、A!=B、A>B、A<B

if(A){} // 先把A轉換爲布爾類型,判斷真假以此來決定是否成立

//否成立

if(A>B&&A<10){} //只有兩個小條件都是真,總體條件爲真

if(A>B||A<10){}  // 只要其中一個小條件成立,總體條件是真
複製代碼

BAT 面試題

var num = parseFloat('width:12.5px');
if(num==12.5){ // =>NaN
	alert(12.5);
}else if(num==NaN){ // NaN!=NaN
	alert(NaN);
}else if(typeof num=='number'){ // 
	alert(0)
}else{
	alert("啥也不是")
}
複製代碼

5.2 三元運算符

條件?條件成立執行:條件不成立執行

if(條件){}else : 三元運算符就是這種簡單if..else..的另外一種寫法

var num = 10;
if(num>5&&num<10){
	num++;//累加1
}else{
	num--;
}
// 修改爲爲三元運算符,若是條件成立或者不成立的某一種狀況並不須要什麼處理
// 咱們空着語法不符合,咱們使用null、undefined、void 0(就是undefined)佔位就能夠
num>5&&num<10?num++:num--;
複製代碼
var num = 10;
if(num>5 && num<10){
	num++;
  break;/continue;/return;
}
// => 修改爲爲三元運算符
// 在三元運算符的操做中不能出現break、continue、return這樣的關鍵詞,因此咱們沒法用三目代替if、else
num>5 && num<10?
(num++,return):null;
複製代碼

5.3 swith case

swith case應用於if、else中一個變量在不一樣值狀況下的不一樣操做

var num =10;
switch(num){
	//switch後面小括號中存放的是一個值(通常咱們都寫變量;把變量存儲的值拿來用,有時候也多是一個計算)
  case 1:
    // case後面放的都是值,目的驗證switch後面的值和哪種case後面的值相等,相等的進行對應的處理
  	...
    break;
    // 每一種case借宿後都要加break借宿當前的判斷
  case 10:
  	...
    break;
  default:
    // switch後面的值和每一種case狀況對應的值都不相等,執行最後的default,相似於false
    ...
}
複製代碼

案例分析

var num = 5;
switch(num%2){//=>先把取餘操做進行運算,拿運算結果case比較
	case 0:
  num++;
  break;  //不加break,無論後面的條件是夠成立,都會繼續向下執行,知道遇到break爲止
    			// 不加break,就能夠實現||這樣的操做
  case: 2-1: //case後面也應該是值,此處先把2-1計算,把計算的結果和switch值比較
  num--;
  // 最後一項能夠不加break,不加也能跳出判斷
  break;
}
num%2:讓num存儲的值除以2去餘數(0或者1)
複製代碼

swich case 中的比較實用的"==="

  • =:賦值,等號左邊是變量,右邊是值
  • ==:比較,若是左邊兩邊的類型不同,瀏覽器默認轉換爲同樣的而後再進行比較  '6'==6  => 6==6 =>true
  • ===:絕對相等,不只要求值同樣,而且類型也要徹底同樣

5.4 循環操做語句

循環,重複作一件事情

for(設置循環起始值;設置循環執行的條件;步長累加){
	// 循環體:重複作的事情都是在循環體重
}
複製代碼
  • 設置初始值
  • 驗證條件
  • 條件成立,執行循環體:不成立,循環借宿
  • 步長累加
for(;i<5;;){
	consloe.log(i);
  //沒有步長累加,咱們的i永遠是0,循環條件永遠成立「死循環」;
  //項目中不能出現死循環,一旦出現,循環下面的事情都作不了
}
複製代碼

5.4.1 continue

結束本輪循環,繼續執行下一輪:循環體重continue後面的代碼都不會在執行,它會直接的去執行步長,而後進行下一輪

for(var i=0;i<5;i+=2){
	console.log(i)
  continue;
}
複製代碼

5.4.2 break

結束整個循環:循環體重一旦遇到break首前後面代碼不執行了,並且步長累加也不執行了,循環都結束了

for(var i=0;i<5;i+=2){
	console.log(i)
  break;
}
複製代碼

BAT面試題

for(var i=1;i<10;i+=2){
	if(i<5){
  	i++;
    continue;
  }else{
  	i+=3;
    break;
  }
  console.log(i)
}
console.log(i) // =>10
複製代碼

5.4.3 for in

用來遍歷(循環)對象鍵值對的

  • var key;var attr(attribute);
  • 對象中有多少鍵值對,咱們的for in 循環遍歷多少次(多少次)
  • 第一次循環key這個遍歷存儲的都是當前循環這個組鍵值隊的屬性名
  • key存儲的值都是字符串格式的(無論屬性名是否爲數字)
  • 在for in 循環的遍歷時候,大部分瀏覽器都是先把對象中的鍵值對進行排序(把數字屬性的排在前面,而且排列的時候安卓數字由小達大排列),其次在把非數字的屬性名按照以前編寫的順序,循環的時候按照從新排列循序一次遍歷(小數算做字母不要作數字)
var obj = {name:wjw,age:8,0:'wjh',3:'ylp',1:'cx'}
for(var key in obj){
    console.log('ok')
    // key 屬性名 string
    console.log(obj.key)
  	//獲取obj中key這個屬性對應的值 ->undefined <=> obj['key']
    console.log(obj[key]);
  	//->每一次循環把key變臉存儲的值(當前遍歷的屬性名)獲取到放在中括號中,獲取obj對應的屬性值
}
for(var key in obj){
    if(obj.hasOwnProperty(key)){
        
    }
 
}
複製代碼

6 JS的DOM獲取節點

DOM:document object model 文檔對象模型,提供一些屬性和方法可讓咱們去操做DOM元素

image.png

image.png

6.1 節點介紹

node 節點,瀏覽器默認在一個html頁面中的全部內容都是節點(包括標籤、註解、文字文本等)

  • 元素節點:HTML標籤
  • 文本節點:文字內容(大部分瀏覽器會把空格和換行也當作文本節點)
  • 註解節點
  • document文檔節點

元素節點

  • nodeType:1
    • 屬性含有某個節點的名稱
  • nodeName: 大寫標籤名(在部分瀏覽器的怪異模式下,咱們寫的標籤名是小寫,它獲取的就是小寫...)
    • 對於元素節點,由於自己不直接包含文本,因此nodeValue是不可用的。固然你也能夠在示例中本身寫試試看有什麼結果出現。
    • 對於文本節點,nodeValue=文本值
    • 對於屬性節點,nodeValue=屬性值
  • nodeValue:null
    • 對於元素節點,nodeType=1
    • 對於文本節點,nodeType=3
    • 對於屬性節點,nodeType=2
    • 對於註釋元素,nodeType=8
    • 對於文檔元素,nodeType=9

[curEle].tagName:獲取當前元素的標籤名(獲取的標籤名通常都是大寫)

文本節點

nodeType:3
nodeName:#text
nodeValue:文本內容

註釋節點

nodeType:8
nodeName:#comment
nodeValue:註釋內容

文檔節點

nodeType:9
nodeName:#document
nodeValue:null

<-- div#box>(ul>li{0$}*3)+div{內容$}*3-->
<div id="box">
        <ul>
            <li>01</li>
            <li>02</li>
            <li>03</li>
        </ul>
        <div>內容1</div>
        <div>內容2</div>
        <div>內容3</div>
 </div>
複製代碼

6.2 獲取dom元素

6.2.1 document.getElementById 一個元素

  • 此方法的上下文只能document
  • 一個html頁面中元素的id理論上是不能重複的,若是頁面中ID重複了,咱們得到結果第一個id對應的元素對象
  • 在ie7更低的版本瀏覽器中,會把表單元素的name值當作id來識別使用(項目中儘可能不要讓表單的name和其餘元素的id相同)
  • 若是咱們把js放在結構的下面,咱們能夠直接使用id值獲取這個元素(不須要經過getElementById獲取),並且這種方式會把頁面中全部id是他的元素都獲取到(元素對象,或者集合) => 不推薦
<div id="box1"></div><div id="box2"></div><div id="box1"></div>
<script>
   console.log(box1)    // -> [div#box1, div#box1, box1: div#box1]
</script>
複製代碼
<input id="myInput" type="text" size="20"/><br />
<script> var x=document.getElementsByName("myInput"); </script>
複製代碼

6.2.2 document.getElementClassName 元素集合

  • 上下文是能夠本身來指定
  • 獲取到的結果是一個元素集合(類數組集合)

  • 獲取的結果是集合,哪怕集合中只有一項,咱們想要操做的是這一項(元素對象),須要先從集合中獲取出來,而後再操做
  • 可是真實的項目中咱們常常會經過樣式類名獲取元素,getElementClassName這個方法在ie6-8不兼容的
<input name="myInput" type="text" size="20"/><br /> <script> var x=document.getElementsByName("input"); </script> var bodyBox = document.getElementsByTagName('body'); bodyBox[0].getElementsByTagName('div'); 複製代碼

6.2.3 document.getElementsTagName 元素集合

<input name="myInput" type="text" size="20"/><br />
<script> var x=document.getElementsByName("input"); </script>
複製代碼

6.2.4 document.getElementsByName 節點集合

經過元素的NAME屬性值獲取一組元素(類數組:節點集合NodeList) 他的上下文只能是document

  • IE瀏覽器只能識別表單元素的name屬性值,因此咱們這個方法通常都用來操做表單元素的
  • 獲取html得到body的元素對象
<input name="myInput" type="text" size="20"/><br />
<script> var x=document.getElementsByName("myInput"); </script>
複製代碼

6.2.5 domcument.domcumentElement 獲取整個html的對象

document.documentElement.clientWidth||document.body.clientWidth
 // 獲取當前瀏覽器可視區域的寬度(當前頁面一個屏幕的寬度)
 // =>clientHieght 獲取高度

複製代碼

6.2.6 domcument.body 獲取body對象

6.2.7 domcument.head 獲取整個head對象

6.2.8 [context]querySelector  一個元素對象 / [context]querySelectorAll 獲取元素集合

  • ie6-8不兼容,並且沒有特別好的辦法處理他的兼容,因此這兩個方法通常多用於移動端開發使用

querySelector 獲取一個元素對象
querySelectorAll 獲取的一個元素集合
只要css支持的選擇器,這裏大部分都支持

document.querySelector('#box1');
document.querySelectorAll('.box1');
document.querySelectorAll('div');
document.querySelectorAll('body>div');
document.querySelectorAll('#box1 li');
複製代碼

6.3 節點關係屬性

節點是用來描述頁面中每一部門之間關係的,只要我能夠獲取頁面中的一個頁面,那麼我就能夠經過相關的屬性和方法獲取頁面中全部的節點

image.png

6.3.1 childNodes

獲取當前元素全部的子節點(節點集合:類數組) 注:不只僅是元素子節點,文本、註釋等都會包含在內:子節點說明只是在兒子輩分中查找

6.3.2 children

獲取全部的元素子節點(元素集合) 在IE6-8下獲取的結果和標準瀏覽器中有區別(IE6-8中會把註釋點當作元素節點獲取到)

6.3.3 pareNode

獲取當前元素的父節點(元素對象)

6.3.4 previousibing

獲取當前節點的上一個各個節點上一個哥哥節點(不必定是元素節點也多是文本或者註釋)

6.3.5 nextibling

獲取當前節點的下一個弟弟節點

6.3.6 previousElementbling

獲取當前節點的上一個哥哥元素節點

6.3.7 nextElementsIbling

獲取當前節點下一個弟弟元素節點 IE6-8不兼容

6.3.8 firstChild

當前元素全部子節點中的第一個(也不必定是元素節點,多是文本和註釋)

6.3.9 lastChild

當前元素多有子節點中的最後一個 fistElementChild lastElementChild(IE6-8兼容)

6.4 建立和增長DOM元素

真實項目中,咱們偶爾會在js中動態建立html標籤,而後把其增長到頁面中

6.4.1 document.createElement

在js中動態建立一個html標籤

6.4.2 appendChild

容器.appendChild(新元素) 把當前建立的新元素添加到容器的末尾位置

6.4.3 inserBefore

容器.inserBefore(新元素、老元素) 在當前容器中,把新建立的元素增長到老元素以前

// 建立
var oDiv = document.createElement('div');
oDiv.id='div1';
oDiv.className = 'box';

// 添加到頁面中
document.body.appendChild(oDiv);
document.body.inserBefore(oDiv,box2);
複製代碼
var link = document.createElement('a');
link.href = 'http://www.baidu.com?name=1&age=2#haha'

consloe.dir(link);
// hash:存儲餓哈希值 '#haha'
// hostname:域名 'www.baidu.com'
// pathname:路徑 '/stu/'
// protocol:協議 'http:'
// search:問號傳遞參數值 '?nname=1&age=2'
複製代碼

真實項目中不少須要經過動態建立元素來完成的,其中有一個需求:解析一個url地址每一部分的信息(包括問號傳值的參數值)

  • 純字符串拆分截取
  • 編寫強大的正則,捕獲到須要的結果
  • 經過動態建立一個a標籤,利用a標籤的一些內置屬性來分別獲取每一部分的內容
function queryURLParameter(url){
	var link = document.createElement('a');
  link.href=url;
  
  var search = link.search,
  		obj = {}'
  if(search.length===0) return;
  search = search.substr(1).split(/&|=/g);
  for(var i=0;i<search.length;i+=2){
  	var key = search[i],
    		value = search[i+1];
    obj[key]=value;
  }
  link = null;
  return obj;
}
複製代碼

6.5 修改刪除克隆DOM元素

6.5.1 removeChild

  • 容器.removeChild(元素)
  • 在當前容器中把每個元素移出掉

6.5.2 replaceChild

  • 容器.removeChild(新元素,老元素)
  • 把原有的元素克隆一份如出一轍的,false:只克隆當前元素自己,true:深度克隆,吧當前元素自己以及元素的全部後代都進行克隆

6.5.3 [set/get/remove]Attribute

給當前元素設置/獲取/移出屬性的(通常操做的都是它的自定義屬性)
box.setAttribute('myIndex',0)
box.getAttribute('myIndex')
box.removeAttribute('myIndex')
複製代碼

使用xxx.index=0 和xxx.setAttribute('index',0)這兩種設置自定義屬性的區別

xxx.index : 是吧當前操做的元素當作一個普通對象,爲其設置一個屬性名
xxx.setAttribute:把元素當作特殊的元素對象來處理,設置的自定義屬性是和頁面結構中的DOM元素映射在一塊兒的

JS中獲取的元素對象,咱們能夠把他理解爲兩種角色:

  • 與頁面HTML結構無關的普通對象
  • 與頁面HTML結構存在映射關係的元素對象

元素對象中的內置屬性,大部分都和頁面的標籤存在映射關係:
xxx.style.backgroundColor = 'xxx' 此時不只把js中對象對應的屬性值改變了,並且也會映射到頁面的html標籤上(標籤中有一個style行內樣式,元素的樣式改變了)
xxx.className = 'xxx'此時不只是吧js對象中的屬性值改變了,並且頁面中的標籤增長了class樣式類(能夠看見的)

元素對象中的自定義屬性: xxx.index=0
僅僅是吧js對象中增長了一個屬性名(自定義的),和頁面中的html沒啥關係(在結構上看不見)

xxx.setAttribute:經過這種方式設置的自定義屬性和以前提到的內置屬性差很少,都是和html結構存在映射關係的(設置的自定屬性能夠呈如今結構上)

6.6 面試題

把當前頁面中全部id叫作box1的都獲取到

var allList = document.getElementsByTagName(*);
var result = []
for(var i=0;i<allList.length;i++){
	var item = allList[i];
  item.id === 'box1'?result.push(item)
}
console.log(result)
複製代碼

獲取當前元素的上一個哥哥元素節點(兼容全部的瀏覽器) curEle:current element

// 首先獲取當前元素的上一個哥哥節點,判斷當前獲取的節點是否爲元素節點(nodeType===1)
// 若是不是基於當前獲取的節點,找他的上一個哥哥節點..(找幾回不知道)一直到找到的節點是元素節點爲止
// 若是在查找過程當中,發現沒有上一個哥哥節點,找到頭了,則再也不繼續查找

function prev(curEle){
	var p = curEle.previousSibling; // 屬性返回同一樹層級中指定節點的前一個節點。
  while(p&&p.nodeType!==1){ //p:p!=null
    p = p.previousSibling;
  }
	return p;
}

// 擴展
// next: 獲取下一個弟弟元素節點
// prevAll:獲取全部的哥哥元素節點
// nextAll:獲取全部的弟弟元素節點
// siblings:獲取全部的兄弟元素節點
// index:獲取當前元素的兄弟中排名索引
複製代碼

7 Math的經常使用方法

7.1 數學函數

可是他是對象數據類型的

  • 'object'
  • Math對象中給咱們提供了不少經常使用操做數字的方法
  • console.dir(Math) // 查看全部方法

7.1.1 abs

Math.abs 取絕對值

7.1.2 cell / floor

cell: 向上取整 floor: 向下取整

7.1.3 round

round: 四捨五入

7.1.4 random

random: 獲取一個[0,1]之間的一個隨機小數

7.1.5 max/minx

max 獲取一組值中的最大值 minx 獲取一組值中的最小值

7.1.6 PI

Math.PI 獲取圓周率

7.1.7 pow / sqrt

pow  獲取一個值的多少冪 sqrt  獲取一個值的開平方

8 字符串及經常使用的方法

在js中用單(雙)引號包裹起來的都是字符串

var str = 'welcome to credan!'
複製代碼

字符串就是由零到多個字符串組成的

第一個字符索引0
第二個字符索引1
...
有length的屬性,存儲的是當前字符串中字符的個數(字符串的長度)

以數字做爲索引,從零開始的

str[0] -> 'w' 第一個字符
strlength-> 46
str[str.length-1] -> '!' 最後一個字符
str[100] -> undefined 若是指定的索引不存在獲取的結果是undefined

真實項目中,咱們常常操做字符串,此時咱們須要掌握經常使用的一些字符牀操做方法

console.dir(String.prototype)

charAt && charCodeAt

8.1 str.charCodeAt(索引):

在charAt 基礎上,把獲取的字符變爲Unicode編碼值(對應ASCll碼錶)

  • 48-57 0-9
  • 65-90 A-Z
  • 97-122 a-z
  • ...

String.fromCharCode(十進制的Unicode值),把值按照ascll碼錶中的信息,轉爲原有字符,charCodeAt正好對應

image.png

8.2 substr && substring && slice

  • 實現字符串截取的三個辦法
  • str.substr(n.m) : 從索引n開始,截取m個字符
  • str.substring(n,m):從索引n開始,截取到索引爲m處(包含m),把找到的部分截取
  • str.slice(n,m):和substring語法意義,區別在於slice支持一負數作索引

image.png

當索引是負數的時候,瀏覽器在處理的時候,是用字符串的總長度加上負數索引,而後按照正數處理操做

細節:

  • 若是隻傳遞了n(str.substr(n)/str.substring(n)),至關於索引n開始的一直截取到字符串的末尾
  • 若是傳遞的索引超出最大限制,也是吧能截取的部分截取掉便可
  • 若是一個參數都不傳遞:至關於吧證書字符串都截取(字符串的克隆)

image.png

indexOf && lastIndexOf

  • str.indexOf 獲取當前字符在字符串中第一次出現位置的索引
  • str.lastIndexOf 獲取的是最後一次出現位置的索引

image.png

若是當前字符在字符串中沒有出現過,結果是-1:咱們根據這個規律可言驗證一下當前字符串中是否包含某個字符

if(str.indexOf('?')===-1){
	// => 沒有出現過
}

if(str.indexOf('?')>=-1){
	// => 出現過
}
複製代碼

8.3 split

str.split 按照某個字符串分紅數組中的某一項,和數組中的join方法是對應

image.png

8.4 replace

str.replace 實現字符的替換 執行一次replace 只能替換一次,若是有好幾個都須要替換,在不適用正則的狀況下,咱們須要執行不少次replace

image.png

有些需求及時執行不少次repalce也實現不了,此時須要使用正則處理,真實項目中replace通常都是和正則搭配使用的

image.png

8.5 trim && trimLeft && trimRight

  • str.trimLeft : 去除字符串開始的口空格
  • str.trimRight : 去除字符串結尾的口空格
  • str.trim 去除字符串首位的空格

image.png

獲取地址欄的值

function queryURLPrameter(url){
	// => url 傳遞的參數
  var quesIndex = url.indexOf('?'),
 		  obj = {}
  if(quesIndex === -1){ // url中沒有問號傳參 直接返回空
  		retrun obj;
  }
  url = url.substr(quesIndex + 1);
  var ary = url.split('&');
  for(var i =0;i<ary.length;i++){
  	var curAry = ary[i].split('=');
    obj[curAry[0]] = curAry[i];
  }
  return obj
}
複製代碼
String.prototype.myQueryURLParameter = function myQueryURLParamter(){
	var obj = /([^=?&]+)=([^=?&]+)/g;
  this.replace(reg,function(){
  	var arg = argments;
    obj[arg[1]] = arg[2]
  })
  return obj;
}

var str = 'https://www/baidu.com/s?wd=1233213&issp=1';
console.log(str.myQueryURLParameter());
複製代碼

9 Date的基礎知識

9.1 Data 是日期類

經過它能夠對時間進行處理

var time = new Date();
// 獲取當前客戶端本機時間(當前獲取的時間不能做爲重要的參考依據)

// 獲取結果是一個日期格式的對象
// Wed Mar 20 2019 17:37:16 GMT+0800 (中國標準時間)
typeof new Date() -> object


time.getFullYear() 獲取四位數全年
time.getMonth() 獲取月份
time.getDate() 獲取日
time.getDay() 獲取星期(0-6表明週日-週六)
time.getHours() 獲取小時
time.getMinutes() 獲取分鐘
time.getSeconds() 獲取秒
time.getMilliseconds() 獲取毫秒
time.getTime() 獲取當前日期距離'1970-01-01 00:00:00'的毫秒差
複製代碼
var time = new Date('2017-10-22'); 
// 當new Date 中傳遞一個時間格式的字符串,至關於把這個字符串換位標準時間對象
// (轉換完成後,就能夠調取上面咱們講的那些方法)
複製代碼

// 時間格式的字符串
'2017-10-22' (IE下識別不了)
'2017/10/22 16:15:34'
'1508659621314'(若是傳遞的是距離1970年那個毫秒查,也能夠識別轉換的,可是隻能是數字,不能是字符串)

10 數組的函數

10.1 數組的基礎結構

  • 數組也是對象數據類型 typeof [] -> 'object'
  • 數組也是屬性名,只不過屬性名是數字,咱們把數字屬性名稱之爲它的索引:數組是以數字爲索引,索引從零開始,有一個length屬性表明數組的長度

image.png

類數組:相似於數組,可是不是數組

  • 經過getElementsByTageName 獲取的元素集合是類數組
  • 函數中的實參集合argument也是類數組

image.png

// for 循環操做
for(var i =0;i<ary.length;i++){
	console.log(ary[i])
}

// for in 循環操做
for(var key in ary){
	// key:屬性名(數組中的屬性名是索引)
	console.log(ary[key]);
}

// for 循環只能遍歷到數組私有的一些屬性,而for in 循環能夠吧一些自定義的公共屬性也能遍歷到
複製代碼

10.2 數組中的經常使用方法

數組中有不少方法

console.dir(Array.prototype)
複製代碼
  • 方法的意義和做用
  • 方法的形參
  • 方法的返回值
  • 經過此方法,原來的數組是否發生了改變

實現數組的增長、修改、刪除

10.2.1 增長

push : 向數組的末尾追加新內容

參數:一到多個,任何數據類型均可以,想要給數組末尾追加什麼,直接傳遞到push方法中極客,傳遞多個逗號隔開
返回值:新增後數組的長度
原有數組改變了

unshift:向數組開頭追加新內容

參數:須要追加的內容(能夠是多個任何數據類型的值)
返回值:新增後 數組的長度
原來數組改變了

把數組當作一個普通的對象,使用對象鍵值對的操做,給其設置新的屬性(索引)
ary[ary.length]=xxx 向數組的末尾追加了新的內容

10.2.2 刪除

pop 刪除數組最後一項

參數:無
返回值:被刪除的那一項內容
原有數組改變了

shift:刪除數組第一項

參數:無
返回值:被刪除那一項的內容
原有數組改變了
使用shift刪除第一項以後,後面每一項的索引都要向前進一位(致使後面項的索引起生了改變)

把數組當作一個普通對象操做
delete刪除:delete ary[索引]刪除指定索引這一項(當前項被刪除後),原有數組其它項的索引不會改變:當前數組的length也不會改變

ary.length--:刪除數組最後一項

splice:數組中內置的方法,能夠實現數組的增長、修改、刪除

splice實現刪除
splice(n,m):從索引n開始刪除m個(m不寫是個刪除列數組的末尾,n也不寫)
返回值:被刪除的內容(以一個新數組保存)
原有數組改變了
splice(0) 清空數組
splice() 一項都不刪除,返回一個新的空數組
splice(0,1)刪除第一項

splice實現修改

splice(n,m,x):在原有刪除的基礎上,用x代替刪除的內容

splice實現增長
splice(n,0,x):在修改的基礎上,咱們一項都不刪除,把x插入到索引n的前面
ary.splice(0,0,x)  向數組末尾追加新元素

數組的查詢

slice 數組的查詢
  • 參數:slice(n,m) 從索引n開始找到索引m處(不包含m)
  • 返回值:吧找到的部分已一個新數組返回
  • 原來的數組不變

slice(n) 從索引n開始找到末尾
slice(0) /slice() 數組克隆,克隆一份和原來數組如出一轍的的新數組
slice支持負載索引,若是傳遞的索引爲負數,瀏覽器解析的時候是按照總長度+負數索引 來處理的

將兩個數組進行拼接

concat:將多個數組拼接在一塊兒

  • 參數:要拼接的內容(把內容放在原數組的後面),能夠是一個數組
  • 返回:拼接後的新數組

原有數組不變

image.png

10.3 數組的查詢

slice: 數組的查詢
參數: slice(n,m) 從索引n開始找到索引爲m處(不包含m)
返回值:把找到的部分已一個新數組返回
原來的數組不變

slice(n) 從索引n開始找到末尾
slice(0) / slice() 數組克隆,克隆一份和原來數組如出一轍的新數組
slice 支持負數索引,若是傳遞的索引爲負數,瀏覽器解析的時候是按照,總長度+負數索引 來處理的
複製代碼

10.4 數組的拼接

concat:將多個數組拼接在一塊兒
參數:要拼接的內容(把內容放在原數組的後面),能夠是一個數組,也能夠是一些數據值
返回:拼接後的新數組
原有的數組不變

let arr = [0,100]
arr.concat([100,200],[200,300],12)
複製代碼

concat() 什麼都沒有拼接,至關於吧原有數組克隆一份如出一轍的出來

image.png

10.5 數組轉字符串

10.5.1 toString

實現吧數組轉化爲字符串(轉換後的字符串逗號分隔每一項)

參數:無
返回值:轉換的字符串
原有數組不變

10.5.2 join

把數組按照指定的分隔符轉換爲字符串,和字符串中的split相對應

  • 參數:指定的連接符號
  • 返回值:轉換後的字符串
  • 原有數組不變

image.png

已知數組的每一項都是數字,想事先數組求和,咱們如何實現?

循環實現

var total = null;
for(var i=0;i<ary.length;i++){
	total+=ary[i];
}
複製代碼

利用join

var total = eval(ary.join('+')) // evel:把字符串變爲js表達式執行
複製代碼

10.6 實現數組中每一項的排序和排列

10.6.1 reverse

把數組中每一項倒過來排序

參數:無
返回值:排序後的數組
原有數組改變

10.6.2 sort

實現數組的排序

參數:無或者回調函數
返回值:排序後的數組
原有數組改變
      不傳遞參數的狀況下:能夠給10之內的數字進行升序排列,可是超過10的就沒法處理(多位數值識別第一位)

ary.sort(function(a,b){
	return a-b; //升序
  return b-a; //降序
})
複製代碼

10.7 驗證數組中是否包含某一項

10.7.1 indexOf / lastindexOf

獲取當前如今數組中第一次或者最後一次出現的位置索引

  • 數組的這兩個方法在IE6-IE8下不兼容
  • 字符串的這兩個方法兼容全部的瀏覽器
if(ary.indexOf(12)>-1){
	// 數組中包含12
}
複製代碼

10.7.2 原理

Array.prototype.myIndexOf = function myIndexOf(value){
	var result = -1;
  for(var i =0;i<this.length;i++){
  	if(value===this[i]){
    	result = i;
      break;
    }
  }
  return result;
}
複製代碼

10.8 遍歷數組每一項的方法

如下方法ie6-8下都不兼容

10.8.1 forEach

遍歷數組中的每一項

ary.forEach(function(value,index){
	/* 數組中有多少項,當前回調函數執行多少次,妹妹一次傳進來的value就是當前遍歷數組這一項的值,index 就是遍歷這一項的索引 */
})
複製代碼

10.8.2 map

遍歷數組中的每一項,在forEach的基礎上,能夠修改每一項的值

ary.map(function(value,index){
	/* 數組中有多少項,當前回調函數執行多少次,妹妹一次傳進來的value就是當前遍歷數組這一項的值,index 就是遍歷這一項的索引 */
  return xxx;
  // return 後面返回的結果就是當前遍歷的這一項修改成xxx
})
複製代碼

filter
find
reduce
every
...

10.9 數組去重

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

方案一 最簡單數組去重法

遍歷數組的每一項,拿每一項和它後面的項依次比較,若是相同了,則把相同的這一項在原來數組中刪除便可

/* * 新建一新數組,遍歷傳入數組,值不在新數組就push進該新數組中 * IE8如下不支持數組的indexOf方法 * */
function uniq(array){
    var temp = []; //一個新的臨時數組
    for(var i = 0; i < array.length; i++){
        if(temp.indexOf(array[i]) == -1){
            temp.push(array[i]);
        }
    }
    return temp;
}

var aa = [1,2,2,4,9,6,7,5,2,3,5,6,5];
console.log(uniq(aa));
複製代碼

方案二 對象鍵值法去重

/* * 速度最快, 佔空間最多(空間換時間) * * 該方法執行的速度比其餘任何方法都快, 就是佔用的內存大一些。 * 現思路:新建一js對象以及新數組,遍歷傳入數組時,判斷值是否爲js對象的鍵, * 不是的話給對象新增該鍵並放入新數組。 * 注意點:判斷是否爲js對象鍵時,會自動對傳入的鍵執行「toString()」, * 不一樣的鍵可能會被誤認爲同樣,例如n[val]-- n[1]、n["1"]; * 解決上述問題仍是得調用「indexOf」。*/
function uniq(array){
    var temp = {}, r = [], len = array.length, val, type;
    for (var i = 0; i < len; i++) {
        val = array[i];
        type = typeof val;
        if (!temp[val]) {
            temp[val] = [type];
            r.push(val);
        } else if (temp[val].indexOf(type) < 0) {
            temp[val].push(type);
            r.push(val);
        }
    }
    return r;
}

var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
console.log(uniq(aa));
複製代碼

方案三 排序後相鄰去除法

/* * 給傳入數組排序,排序後相同值相鄰, * 而後遍歷時,新數組只加入不與前一值重複的值。 * 會打亂原來數組的順序 * */
function uniq(array){
    array.sort();
    var temp=[array[0]];
    for(var i = 1; i < array.length; i++){
        if( array[i] !== temp[temp.length-1]){
            temp.push(array[i]);
        }
    }
    return temp;
}

var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
console.log(uniq(aa));
複製代碼

方案四  數組下標法

/* * * 仍是得調用「indexOf」性能跟方法1差很少, * 實現思路:若是當前數組的第i項在當前數組中第一次出現的位置不是i, * 那麼表示第i項是重複的,忽略掉。不然存入結果數組。 * */
function uniq(array){
    var temp = [];
    for(var i = 0; i < array.length; i++) {
        //若是當前數組的第i項在當前數組中第一次出現的位置是i,才存入數組;不然表明是重複的
        if(array.indexOf(array[i]) == i){
            temp.push(array[i])
        }
    }
    return temp;
}

var aa = [1,2,"2",4,9,"a","a",2,3,5,6,5];
console.log(uniq(aa));
複製代碼

方案五  優化遍歷數組法

// 思路:獲取沒重複的最右一值放入新數組
/* * 推薦的方法 * * 方法的實現代碼至關酷炫, * 實現思路:獲取沒重複的最右一值放入新數組。 * (檢測到有重複值時終止當前循環同時進入頂層循環的下一輪判斷)*/
function uniq(array){
    var temp = [];
    var index = [];
    var l = array.length;
    for(var i = 0; i < l; i++) {
        for(var j = i + 1; j < l; j++){
            if (array[i] === array[j]){
                i++;
                j = i;
            }
        }
        temp.push(array[i]);
        index.push(i);
    }
    console.log(index);
    return temp;
}

var aa = [1,2,2,3,5,3,6,5];
console.log(uniq(aa));
複製代碼

11 函數基礎

  • 函數是指一段在一塊兒的、能夠作某一件事兒的程序。也叫作子程序、(OOP中)方法
  • 函數實現某一個功能的方法

11.1 建立函數

functoin [函數名](){
		// => [函數體]
    // 實現功能的具體js代碼
}
複製代碼

11.2 執行函數

函數名(); // 建立的函數執行,並且這個函數能夠執行不少次
函數名();
複製代碼

每一次執行都至關於把函數體重實現功能的js代碼重複執行了一遍

在真實的項目中,咱們通常都會把實現一個具體功能的代碼封裝到函數中

  • 若是當前這個功能須要在頁面中執行屢次,不封裝成爲函數,每一次實現這個功能,都須要從新吧代碼寫一遍,浪費時間;而封裝在一個函數中,之後想實現屢次這個功能,咱們就沒有必要在從新寫代碼,只須要把函數從新的執行便可,提升了開發效率
  • 封裝在一個函數,頁面中就基本上很難重複同樣的代碼了,減小了頁面中代碼的冗餘度,提升了代碼的重複利用率: 低耦合高內聚

咱們把以上的特色成爲函數封裝 (OOP面向對象編程思想,須要咱們掌握的就是類的繼承、封裝、多態)

11.3 JS中函數的核心原理

函數做爲js中引用數據類型中的一種,也是按照引用地址操做的

function sum(){
	var total = 1+1;
  total *= 20;
  console.log(total.toFixed(2));
}
sum();
複製代碼

11.3.1 建立函數

  • 首先會在當前做用中聲明一個函數名(聲明的函數和使用var聲明變量是同樣的操做:var sum;function cum;這兩個名字算重複了)
  • 瀏覽器首先會開闢一個新的內存空間(奉陪一個16進制地址),把函數體重寫好的代碼當作普通字符串存儲在這個內存空間(建立一個函數若是不執行,函數沒有意義)
  • 把內存空間的地址賦值給以前聲明的那個函數名

11.3.2 函數執行

  • 目的:把以前存儲的實現具體功能的js代碼執行
  • 函數執行,瀏覽器首先會爲其開闢新的私有做用域(只能執行函數中以前編寫的js代碼)
  • 形參賦值
  • 私有做用中的變量升級
  • 把以前穿件時間存儲的那些js代碼字符串,拿到自由做用域中,而後把題目變成js表達式從上到下執行
  • 私有做用域是否銷燬的問題

![image.png](https://cdn.nlark.com/yuque/0/2019/png/271124/1553076800854-5e22d4eb-aa50-40a1-a8de-6abbd5cf8939.png#align=left&display=inline&height=203&name=image.png&originHeight=406&originWidth=986&size=115231&status=done&width=493)

11.3.3 閉包

函數執行會造成一個私有的做用域,讓裏面的私有變量和外界互不影響(相互干擾、外面的沒法直接獲取裏面的變量值),此時咱們能夠理解爲私有做用域把私有變量保護起來,咱們把這種保護機制稱爲爲閉包

11.3.4 棧內存

做用域(全局做用域/私有做用域):提供一個供js代碼執行的環境

11.3.5 堆內存

全部的引用數據類型,他們須要存儲的內容都是堆內存中(至關於一個倉庫,目的是存儲信息)

  • 對象會吧鍵值隊存儲起來
  • 函數會把代碼當作字符串存儲起來

11.4 函數中形參和實參

  • 形參:至關於生成洗衣機的時候提供的入口,須要用戶執行函數的時候把須要的值傳遞進來,形參是個變量,用來春初和接口那些值
  • 實參:用戶執行的時候傳遞給形參的具體指
// 隨便求出兩個數的和

function sum(num1,num2){ //num1/num2就是形參變量(相似於var了一下)
		var total = num1 + num2;
    total*=10;
    total=total.toFixed(2);
		console.log(total);
}

sum(10,20);//10/20是實參 num1=10 num2=20
sum(10); // num1=10 num2=undefined 定義了形參可是執行的時候,沒有傳遞實參,默認實參就是undefined
複製代碼

11.5 arguments實參集合

當咱們不知道用戶具體要傳遞幾個值的時候(傳遞幾個值都行),此時咱們沒法設置形參的個數:遇到此類須要,須要使用函數內置的實參集合:arguments

  • argument 只有函數纔有
  • 無論執行函數的時候是否傳遞實參,arguments天生就純在,沒有傳遞實參ARG是個空的集合傳遞了ARG中包含了全部傳遞的實參值
  • 無論是否設置了形參,ARG中始終存儲了全部的實參信息
function sum(){
	console.log(arguments)
}
sum(10,20,'wjh',{name:'wjw'});
複製代碼

image.png

  • arguments 是個類數組集合
    • 以數字做爲索引(屬性名),從0開始
    • arguments[0] 第一個實參信息
    • arguments[2] 第三個實參信息
    • arguments[n] 第n+1個實參信息
  • 有一個length的屬性,存儲的是當前幾個的長度(當前傳遞實參的個數)
    • arguments.length
    • arguments['length']
    • arguments.calle 存儲的是當前函數自己
    • arguments.calle.caller 存儲的是當前函數只在哪執行的(宿主函數),在全局做用域下執行的,結果是null
function sum(){
	console.log(arguments.callee.caller);//f
}
function fn(){
	sum(10,20,'wjh',{name:'wjw'});
}
fn();
複製代碼

// arguments.call或者arguments.call.caller通常真正項目中不多使用,由於是在嚴格js模式下不容許咱們直接使用這兩個屬性,然而現有項目大部分都是基於嚴格模式來的

// 任意數求和

function sum(){
	var total = null;
  for(var i =0;i<arguments.length;i++){
  	var cur = Number(arguments[i]);
    !isNaN(cur)?total += cur : null
  }
  consloe.log(total);
  return total;
  // return 後面跟着的都是值(返回的都是值):此處很多TOTAL變量返回,而是吧total存儲到值返回而已
  // return 60;
}
sum(10,20,20);
sum();
sum(10,20,30,'wjw')
// console.log(total); 
//=>Uncaught ReferenceError: total is not defined 閉包的保護機制致使做用域會保護裏面的私有變量
複製代碼

11.6 JS中的返回值return

返回值是函數提供的一個出口:咱們若是想在外面使用函數私有的一些信息,那麼就須要經過return,把這些信息返回出來供外面使用

sum:表明的是函數自己
sum() 讓函數先執行,表明的是當前函數返回的結果(return)後面是啥,至關於函數返回的是啥

function sum(){
		var total = 0;
    renturn
}
console.log(sum());
// 若是函數中沒有return或者return後面啥也沒有,默認返回的結果是undefined
複製代碼
function sum(){
		var total = 0;
    renturn;
    console.log(sum());
  	// 函數體重遇到return後,return後面的代碼都不在執行了
}
複製代碼

11.7 js中匿名函數

沒有名字的函數

  • 函數表達式
  • 自執行函數
oBox.onclick = function(){
	// 把一個碼雲名字的函數(有名字的也無所謂)做爲值賦值給一個變量或者一個元素的某一個事件等,函數表達式

}
複製代碼
(function(n){
	// 建立函數和執行函數放在一塊兒,穿件完成立馬之執行:自執行函數
  // n 形參 n=10
})(10)

// 如下都是自執行函數,符號只有控制語法規範
~function(){}(10)
-function(){}(10)
+function(){}(10)
!function(){}(10)
複製代碼
相關文章
相關標籤/搜索