JS基礎之數組和函數

1、Array

什麼是數組?

1.從人類的角度看,數組是按次序排列的一組值。
2.從JS的角度看,是用Array定義的一個對象。
Array.prototype{.push(),.pop(),.shift(),.join(),...}面試

1.基礎用法

用法1:var a = Array[3],獲得的是長度爲3的數組,且值爲undefined。
用法2:var a = Array[3,3],獲得的是長度爲2,值爲{3,3}的數組。編程

```
Array(2)  
0:3  
1:3  
length:2
__proto__:Array(0)
```
複製代碼

小總結: 數組

2.數組和對象的區別

對比:a=[1,2,3] 和 object={0:1 1:2 2:3 length=3 }
本質區別:他們的__proto__指向不一樣即原型鏈不一樣,如圖所示: bash


實際上,數組是否是數組,取決於使用者要不要把它當成數組:

var obj = {
    0:1, 1:2, 2:3 ,3:4, length:4
}
當成數組:
for(let i=0; i<obj.length;i++){
    console.log(obj[i])
}
當成對象:
for(let i in obj){
    console.log(obj[i])
}
複製代碼

3.僞數組

定義:原型鏈(_proto_)沒有Array.prototype,那這個對象就是僞數組。
用途:目前JS只有一個僞數組arguments(arguments就是接收到的參數)閉包

function (){
    console.dir(arguments)
}
f(1,2,3)
>> Argument(3)
    0:1
    1:2
    2:3
    callee:f f()
    length:3
    Symbol(symbol.iterator):f value()
    __proto__:Object
複製代碼

4.Array.API

  1. a.forEach:用於調用數組的每一個元素,並將元素傳遞給回調函數。
function forEach(array,fn){ // 遍歷這個數組,並將值傳遞給fn,故fn必須接收兩個參數(具體看文檔)
    for(let i=0; i<array.length;i++){
        fn(array[i],i) //fn(value,key)
    }
}
var a=['a','b','c']
a.forEach(function(value,key){ //此處value、key就是從a傳遞過來的參數
    console.log(value,key)
})
結果:
      a 0
      b 1
      c 2
      undefined
注意:在JS中,a.forEach(fn)自動把數組a的每一個元素傳遞給fn。(利用this)
複製代碼

一句話結論:a.forEach接收一個函數,這個函數必須接收三個參數,依次是a的value、key和a自己,且返回值是undefinedapp

a=['fff','jjj','kkk']
a.forEach(function(b,c,d){
    console.log(b,c,d)    
})
結果:
    fff 0 (3) ['fff','jjj','kkk']
    jjj 1 (3) ['fff','jjj','kkk']
    kkk 2 (3) ['fff','jjj','kkk']
複製代碼
  1. a.sort:數組排序(通常是快排)(會改變原數組)
原理:a.sort接收一個函數,這個函數必須接收兩個參數x、y,返回值有三種:
①a.sort(function(x,y){return x-y})              此爲從小到大排列
    返回值>0, 表示前面數字大,要放後面。
    返回值=0,表示兩個數字位置相等。
    返回值<0. 表示前面數字小,要放前面
    
②a.sort(function(x,y){return y-x})              此爲從大到小排列
    同理,此處x-y變成y-x
    
實際應用中,可二者都試一試,哪一個結果是咱們想要的就用哪一個。  

例子:
    a = ['馬雲''馬化騰','李彥宏'],按照財富值從大到小排列
    hash = {
        '馬雲':167,
        '馬化騰':376,
        '李彥宏':228
    }
    a.sort(function(x,y){return hash[x] - hash[y]}) 
    結果:['馬雲''李彥宏','馬化騰'] // 這個結果是錯的,因此x-y不行,改爲y-x
    a.sort(function(x,y){return hash[y] - hash[x]}) 
    結果:'馬化騰','李彥宏',['馬雲']
複製代碼

實際使用sort排序時,要給一個誰大誰小的憑證,如例子中的hash,雖然a中是人名沒法直接比較,可是咱們憑藉hash排出了順序,x-y不行就用y-x就行了。
3. a.join:在a的每一個元素之間插入參數函數

a=[1,2,3]
a.join(插入)
結果:"1插入2插入3"
經常使用於數組變字符串:a.join(,) 等價於 a + ''
複製代碼
  1. a.concat:合併多個數組;合併多個字符串;鏈接多個數組
普通用法:
        var a = [1,2,3]
        var b = [4,5,6]
        a.concat(b)
        結果:[1,2,3,4,5,6]
特殊用法:複製一個數組,且複製的數組與原數組不相等
        var a = [1,2,3]
        var b = a.concat([])
        a === b // false
        var c = a 
        c == a // true
複製代碼
  1. a.map:功能與a.forEach徹底相同,但返回值不是undefined,而是將函數返回的每個值收集起來組成一個新的數組,新數組的長度與原數組相同。(map爲映射的意思)
a = [1,2,3]
a.forEach(function(){}) // >undefined
a.map(function(value,key){
    return value * 2
})                     // > [2,4,6]
轉換爲箭頭函數:a.map(value => value*2)
複製代碼

      return的格式無限制,可根據實際需求寫返回值的格式。
6. a.filter:filter是過濾的意思,根據return的條件篩選出元素並組成一個新的數組。網站

a = [1,2,3,4,5,6,7,8,9,10]
a.filter(function(value,key){
    return value % 2 === 0 //除以2的餘數爲0,即偶數
})
結果:
    [2,4,6,8,10]
    
filter與map連用:
a = [1,2,3,4,5,6,7,8,9,10]
a.filter(function(value,key){
    return value % 2 === 0         
}).map(function(value,key){    //[2,4,6,8,10].map...
    return value * value
})
結果:
    [4,16,36,64,100]
複製代碼
  1. a.reduce:遍歷數組a,每一次都取一個結果,並把這個結果放在下一項上。
a = [1,2,3]
a.reduce(function (sum,n){  // 求數組a的元素總和
    return sum + n 
},0)
此處function也必須接收兩個值,一個是sum,一個是n;除function外還要接收一個初始值sum=0
轉換爲箭頭函數:a.reduce((sum,n) => sum + n,0)
複製代碼

總結:

  1. map 能夠用 reduce 表示
a = [1,2,3]                          //每項元素乘2
a.reduce(function(arr,n){ //arr是上一次的數組,n是數組a的每一個元素
    arr.push(n*2)
    return arr
},[])
結果:
    [2,4,6]
複製代碼
  1. filter 能夠用 reduce 表示
a = [1,2,3,4,5,6,7,8,9,10]           //找出偶數
a.reduce(function(arr,n){ //arr是上一次的數組,n是數組a的每一個元素
    if(n % 2 === 0){
        arr.push(n)
    }
    return arr
},[])
結果:
    [2,4,6,8,10]
複製代碼

2、Function

Function.prototype{.call(),.bind(),.apply()}
用法:new Function ([[參數1,參數2,...,參數n],]函數體)
   注:[..]內的內容爲可選內容,無關緊要。
例如:var f = new Function('a','b','return a+b')
          f(1,2)=>3ui

  • function x 是一個特殊的變量,就是對象中的函數。
  • function 是一個關鍵字,用來聲明一個函數:function f(){}
    Function 是一個全局變量,用法爲:var f = new Function('x','y','x+y')
    注意基礎概念來進行區分。

1. 函數聲明的五種方式

  1. 具名函數:直接一步到位
function f(x,y){
    return x+y
}
f.name // 'f'
複製代碼
  1. 匿名函數:匿名函數沒法直接聲明,因此要先聲明一個變量,而後將匿名函數賦給該函數
var f
f = function (){
    teturn
}
f.name // 'f'
複製代碼
  1. 具名函數賦值
var f
 f = function f2(x,y){ return x+y }
 f.name // 'f2'
 console.log(f2) // undefined   面試題
複製代碼

  1. window.function:此法通常不用
var f = new Function('x','y','return x+y')
//括號內都是字符串,字符串之間能夠拼接插入變量,好比n=1,'return x+'+n+'+y' === return x+1+y
 f.name // "anonymous" (翻譯:匿名的)
複製代碼
  1. 箭頭函數
var f = (x,y) => {
     return x+y
 }
 ① var sum = (x,y) => {return x+y} 
 ② 若大括號內只有一句話,則可去掉大括號和return,即
    var sum = (x,y) => x+y
 ③ 若小括號裏只有一個參數,則可去掉小括號,即 
    var n2 = n => n*n
注:1. => 中間不能有空格
    2. 複雜時,只須要加分號便可,JS裏換行不換行沒有意義。
複製代碼

2. 函數調用

聲明:爲了學會後面的this,必定要學會硬核的函數調用方法,如圖: this

  1. f.call(asThis, input1,input2)
  • 其中 asThis 會被當作 this,[input1,input2] 會被當作 arguments
  • 禁止使用 f(input1, input2),由於學會 .call 才能理解 this
function f(x,y){return x+y}
f.call(undefined, 1,2)  
結果:3
複製代碼
  • this:就是.call的第一個參數;
    註釋:通常模式下,this是undefined就自動轉換爲window;在'use strict'下,就是undefined。
  • arguments:.call的第二個及之後的參數組成僞數組
  1. f(input1,input2)
    這是新手或者說是更加經常使用的函數調用方法,這種方法的參數就是arguments,this參數被隱藏了,知道f()和f.call()的區別就能夠了。
  2. call stack 調用棧
    每次進一個函數,就要壓一次stack,直到stack overflow即超過了棧的存儲空間 !
  • stackoverflow.com 是一個編程出BUG問題總結的網站,出現BUG時,能夠去這個網站看看。

3、做用域面試題

  • 按照語法樹,就近原則
  • 咱們只能肯定變量是哪一個變量,可是不能肯定變量的值

第一題:

找一個變量的值,首先在本做用域找,找不到再去父親的做用域找。
變形一:

var a= 1 //若去除此句,則下方a=2則是聲明並賦值
function f1(){
    a = 2 // 此處是給全局的a賦值爲3
    f2.call()
    console.log(a)
    
    function f2(){
        var a = 3
        console.log(a)
    }
}

f1.call()
console.log(a)
複製代碼

看到代碼,必定要先變量提高!變量提高!變量提高! 變形二:

var a= 1 
function f1(){
    f2.call()
    console.log(a)
    var a = 2 
    
    function f2(){
        var a = 3
        console.log(a)
    }
}

f1.call()
console.log(a)
複製代碼

拿到題,首先作變量提高!提高後結果爲:

var a= 1 
function f1(){
    var a
    function f2(){
        var a = 3
        console.log(a) // a === 3
    }
    f2.call()
    console.log(a) // a === undefined 此處a已聲明但未賦值,因此是undefined
    a = 2 
    
    
}

f1.call()
console.log(a) // a === 1
複製代碼

第二題:

var a= 1 
function f1(){
    console.log(a)
    var a = 2
    f2.call()
}    
function f2(){
    console.log(a) // a === 1 f2中沒有a,找它的父做用域即全局做用域,找到a=1
}


f1.call()
console.log(a)
複製代碼

第三題:

var a = 1
function f1(){
    console.log(a) //a === 1 ?
}

??????       // 這是一行被遮住的代碼
f4.call()
複製代碼

如題,若被遮住的代碼是 a=2 ,那麼f1中的a就是2了。

易錯題:

當點擊選項3的時候,會打印出幾呢?
答案是 6 !
必定要明白,i是哪一個i,而i的值又是哪一個值,這一切都要結合做用域來理解。

  • 閉包 若是一個函數,使用了它做用域以外的變量,那麼(這個函數+這個變量)就叫作閉包。 (搜索:方應杭 閉包)
相關文章
相關標籤/搜索