天天看點

javascript深入學習之二

call深入了解

  • call方法的作用:
    • 首先我們讓原型上的call方法執行,在執行call方法的時候,讓我們的fn方法中的this變為第一個參數值obj,然後再把這個函數執行

      fn.call(ibj)

function fn () {
    console.log(this)
}
//自己模拟内置call方法
Function.prototype.myCall = function (content) {
    //-> myCall方法中的this關鍵字變為context的值->obj
    //-> 讓this這個函數中的"this"關鍵字變為context
    //eval(this.toString().replace('this', 'obj'))
    //-> 讓fn方法執行

}
fn.myCall(obj) //方法中的this是fn
my.myCall(obj) //方法中的this是my

function fn1() {console.log(, this)}
function fn2() {console.log(, this)}
fn1() // window
fn2() // window
fn1.call(fn2) //方法首先在執行的時候按照原型鍊機制,找到Function.prototype 上的call方法,執行call方法,此時call方法中的this是我們要操作的fn1,在call方法執行的過程中首先讓‘this’關鍵字變為fn2,然後執行fn1方法 -> , fn2

//隻要出現一下多個(兩個以上都是)call的情況下,調用的都是後邊的方法,fn1隻是用來查找call的方法
fn1.call.call.call(fn2) //fn2()
//執行過程
找到fn1原型上的call -> this -> fn1.prototype
在this.call -> 通過原型鍊機制從原型上找到自己
在this.call -> 通過原型鍊機制從原型上找到自己
this -> this = fn2
this()
           

call、apply、bind的差別

  • apply和call方法的作用完全相同,都是改變this關鍵字并且執行方法,而且在嚴格模式和非嚴格模式下對于第一個參數特殊值的處理是一樣的,
  • apply和call的差別在于call給fn傳遞參數的時候是一個一個的傳遞,apply傳遞值是把要傳遞的值統一放在一個數組裡邊,進行操作,但是也相當于一個一個的傳參
  • 使用場景,給fn傳參比較少,并且确定的情況下使用call,參數較多或者不确定的時候使用apply
  • bind方法:這個方法在IE-6-8不相容,-> 和call、apply作用類似,用來改變this關鍵字,差別在于bind方法隻是改變this關鍵字,并沒有立即執行函數,執行bind會有一個傳回值,就是改變this後的傳回目前函數,
  • 預處理:事先改變為我們想要的結果,在需要的用到的時候,就可以直接調用
var obj = {name: 'leo', age: }
    function fn (n1, n2) {console.log(this, n1 + n2)}

    //在非嚴格模式下, 我們第一個參數傳什麼值,函數裡的this就是什麼值,預設不寫或者是null, undefined的情況下都是window
    fn(, ) //window 5
    fn.call(, ) //2 NAN
    fn.call(obj, , ) //obj 5
    fn.call() //window
    fn.call(null) //window
    fn.call(undefined) //window

    //在嚴格模式下 ‘use strict’
    //傳誰就是誰,不傳就是undefined
    fn.call() // undefined
    fn.call(null) //null
    fn.call(undefined) //undefined

    var tempFn = fn.bind(obj, , )
    tempFn() //obj , 3
           

擷取數組中的最大/最小值

var arr = [,, , , , , ]
。數組排序法 ->數組排序->擷取arr的第一個和最後一個
arr.sort(function (a, b) {return a - b})
var min = arr.shift()
var max = arr.pop()

使用Math對象的min和max方法
//思路:調用Math.min方法,因為min、max需要一個的進行傳參,顧使用apply修改this > Math.min.apply(window, arr)
var min = Math.min.apply(window, arr)
var max = Math.max.apply(window, arr)

假設發,假設數組中的第一個值就是最大/最小值然後和其他值做對比
var max = arr[]
for (var i =; i< arr.length; i++) {
    if (max < arr[i]) max = arr[i]
}

var min = arr[]
for (var i =; i< arr.length; i++) {
    if (min > arr[i]) min = arr[i]
}

eval實作,首先進行字元串拼接,把“Math.min(“ + arr.toString()+  ”)“
然後使用eval解析這個字元串
var max = eval("Math.max(" + arr.toString()+  ")“)
var min = eval("Math.min(" + arr.toString()+  ")“)

//括号表達式,裡邊的内容用","号隔開,執行的時候隻取最後一項
(fn1,fn2)() // fn2()
           

擷取數組中的平均值

//去掉一個最高分,去掉一個最低分,取平均分
//實作思路,首先對數組機型排序,然後使用arr.jion方法使用‘+’拼接字元串,最後用eval執行
var arr = [, , , , , ]
數組排序
arr.sort(function (a, b) {return a* -b*})
//因為js浮點數的機制,可能沒法排序,使用假小數點後邊保留兩位,那麼使用‘*100‘修正
去除最低分
arr.shit()
去除最高分
arr.pop()
得到平均樹
var num = (eval(arr.join('+'))/arr.length).toFixed()

//累數組轉換為數組
var fn = function () {
    var agv = arguments
    //1.//周遊法
    var arr = []

    for (var i=, len = agv.length; i < len ; i++) {
        arr[i] = agv[i]
    }
    //打判斷arr是否為數組
    console.log(arr instanceof Array)
    console.log(Array.prototype.toString.call(arr))
    console.log( typeof arr == "object" && arr.constructor == Array)
    //2.借用數組slice方法
    //var arr = Array.prototype.slice.call(agv)
    //簡寫的方式 可以通過Array的執行個體對象找到Array上的所有方法
    var arr = [].slice.call(agv)
}

//對agv操作的時候可以借用Array上的方法
           

sort 深入學習

  • 回調函數:把一個函數A當做值傳遞給另一個函數B,B方法執行的時候我們根據業務需求決定在某個時機調用函數A
var arr = [, , , , , ]
arr.sort() //在不傳參數的情況下隻能處理10以内的數字排序

arr.sort(function(a, b){
    //a是周遊數組目前項
    //b是數組項a的下一項
    //arr為栗子: a = arr[0] -> b = arr[1]
    //傳回值是 >0 || <= 0

    return a - b //升序
    return b - a //降序
    return (a - b) //降序
})

//多元數組排序
var  arr2 = [
    {name: '張三',age: }, 
    {name: '李思', age: },
    {name: '王武', age: },
    {name: 'leo', age: },
    {name: 'luce', age: },
]

arr2.sort(function (a, b) {
    return a.age - b.age
})

//排序時使用name排序的問題
arr2.sort(function (a, b) {
 //使用localeCompare方法,該方法首先會把目前文字轉換為26拼音,然後按照從前往後周遊,按照英文字母在26的字母的順序傳回,a在b的後邊傳回1,否則傳回-1;如果拼音完全一樣,該方法就會按照文字在Unicode編碼的位置做對比
    return a.name.localeCompare(b.name)
})
})
           

正規表達式

正則: 式就是一種規則,用來處理字元串。  
處理: 1.判斷一個字元串是否符合我們制定的規則。 //reg.test(str)  2.把字元串中符合我們制定的規則的内容捕獲到。 //reg.exec(str)  
           
  • 建立正則
    • 字面量: var reg = /\d+/ig;
    • 執行個體的方式建立: var reg = new RegExp(‘\d’);
  • 元字元: 元字元就是在正規表達式之間具有特殊意義的字元。;每一個正規表達式都由元字元和修飾符組成。
    • : 轉義符,轉義後邊的字元代表的含義
    • ^: 以某個元字元開始
    • $: 以某個元字元結束
    • \n: 比對一個換行符
    • .: 比對除了\n以外的任意字元
    • 代表次數的量詞元字元:
      • *: 出現零到多次
      • +: 出現一到多次
      • ?: 出現零次或者多次
      • {n}: 出現多次
      • {n,}: 至少出現多次
      • {n, m}: 至少出現n次,最多出現m次
    • 分組: 把一個大正則劃分成多個小正則 var reg = /^(\s*) | (\s*)$/;
      • x|y: x或者y中的任意一個;
      • [xyz]: x,y,z 中的任意一個
      • [^xyz]: 除了xyz的其他任意字元
      • [a-z]: 小寫a-z之間的任意字元
      • [^a-z]: 除了小寫a-z之間任意字元的字元
      • \d: 0-9之間的數字
      • \b: 一個邊界符
      • \w: 數字,字母,下劃線中的任意字元; [a-zA-z0-9_]
      • \s: 比對一個 空白祖父,空格,一個制表符,換頁符…
    • 有效的數組正則,正數,負數,零,小數
      • ’.’: 可以出現,但是後邊必須有數字
      • 最開始可以是[+|-],
      • 整數部分:一位可以是0-9,多位的時候第一個不可以是0
      • var reg = /^[+-]?(\d| ([1-9]\d+))(.\d+)$/
  • 正則的兩種建立方式的差別:
  • 在字面量的方式中,//中間的所有字元都是元字元,有的具有特殊意義,大部分是代表本身的普通元字元
  • 字面量的方式中一切都是元字元,是以不能進行字元串拼接。而使用執行個體的方式穿件的時候就可以。
  • 字面量的時候

    \d

    就可以,而執行個體的話需要轉義

    \\d

//簡單的正規表達式
 檢測年齡 -之間 
//思路: 把18-19分為一組,20-59分為一組,60-65分為一組 1[89] | [2-5]\d | 6[0-5]
var reg = /^(1[89]|[2-5]\d|6[0-5])$/
           
  • exec -> 正則捕獲
    • 每一個捕獲都會傳回一個結果,如果捕獲不到比對的内容,就傳回null,如果捕獲到比對的内容傳回一個數組
    • 捕獲内容的格式
      • 捕獲到的内容是一個數組
      • 數組的第一項是目前大正則不活動内容
      • index:數組的第二項是目前捕獲内容的開始下标
      • input:捕獲的原始字元串
    • 正則捕獲的特點
      • 懶惰性 -> 每一次執行exec捕獲第一個比對内容,在不進行任何處理的情況下,執行多次比對得到的結果始終是第一個比對結果。
      • lastIndex:是正則每一次在字元串中開始纏着的位置,預設值是0;每次捕獲都會從lastIndex的位置開始,如果我沒不做特殊的處理,lastIndex永遠是0;
      • 解決正則的懶惰性:在正規表達式的後邊添加修飾符g
      • 原理:加了全局修飾符,正則每一次捕獲結束以後,lastIndex會變為最新的值,下一次不過從最新的位置開始
      • 修飾符
        • g: globale 代表全局
        • i;ignoreCase 忽略大小寫
        • m: multiline: 多行比對
    • 正則比對的貪婪性:正規表達式每次都會捕獲可以比對的最長的結果,如/\d+/.exec(‘2012hello2017’),2符合比對規則,2012也比對規則,正則比對出來的就是2012,這就是正則的貪婪性。
    • 如何解決正則的貪婪性 -> 在量詞元字元後邊添加一個

      ?

      号即可; 例如/\d+?/g;
    • ?

      号在正則中的作用
      • 放在普通元字元中後邊代表出現0-1次; /\d?/ -> 表示出現0-1次0-9的數字
      • 出現在一個量詞後邊,表示解決正則的貪婪性;/\d+?/g;
      • f
    • 字元串中的match方法可以捕獲所有的正則比對的字元串,傳回一個數組
    • 正則分組
      • 改變優先級
      • 分組引用

        var reg = /^(\w)\1(\w)\2$/

        \1代表和第一個分組出現一模一樣的内容;\2代表和第二個分組出現一模一樣的内容
      • 分組捕獲 -> 正則在捕獲的時候不僅僅吧大正則比對的内容捕獲到而且還可以吧小分組比對的内容捕獲到
      • (?:\d+) -> 表示不比對的内容
//列印每次正則比對的結果
var str = '1234hello490world567'
var reg = /\d+/g;
var arr = []
var res = reg.exec(str)
while(res) {
    arr.push(res[]);
    res = reg.exec(str)
}
console.log(arr)

//字元串中的match方法捕獲所有的比對内容

var str = '1234hello490world567'
var reg = /\d+/g;
//傳回值是一個數組,裡邊是所有正則比對的内容
var arr = str.match(reg)
console.log(arr) // ["1234", "490", "567"]

//注:雖然m字元串的match方法可以捕獲所有的内容,使用起來要不exec友善很多,但是macth中存在一些自己處理不了的問題,在分組捕獲的情況下,match隻能捕獲到大正則比對的内容,而對于小正則捕獲的内容,是無法擷取的。

//正則中的分組捕獲
// \1代表和第一個分組出現一模一樣的内容;
// \2代表和第二個分組出現一模一樣的内容
// 一模一樣:表示裡邊的内容也要一模一樣
var reg = /^(\w)\1(\w)\2$/;
var str = 'hhaa';
console.log(reg.exec(str))

//分組捕獲
var reg = /(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(\d)(\d|X)/g;
var str = '622425199011258339';
var arr = reg.exec(str);  //["6224251990112583", "62", "2425", "1990", "11", "25", "8", "3", index: 0, input: "622425199011258339"]
//arr[0] : 大正則比對的内容
//arr[1] : 第一個分組捕獲的内容
//arr[2] : 第二個分組捕獲的内容
//arr[3] : 第三個分組捕獲的内容
//arr[n] : 第n個分組捕獲的内容
           
  • replace方法 -> 把原有的字元貼換成新的字元,在不使用正則的情況下,replace隻能替換一個字元
    • 正則的原理:首先我們和exec捕獲一樣,把所有的和我們正則比對的都捕獲到,然後把捕獲的内容替換成我們需要替換的内容
    • /\d+/g

      把所有比對的都替換為我們想要的。
    • 當replace方法的第二個參數是一個匿名函數的時候,正則比對了多少個内容,匿名函數就會被調用多少次。
    • 每一次執行匿名函數,傳入的

      arguments

      内容和我們使用正則exec捕獲傳回的内容很相似(即使正則有分組,我們也可以通過

      arguments

      擷取到分組捕獲的内容)
    • return

      —> 傳回什麼,就相當于把比對的内容替換成什麼。
var reg = /\d+/g;
var str = 'hello123hello456hello';
str.replace('hello', 'haha')
//在不使用正則的情況下,replace隻能替換一個字元
console.log(str) //"haha123hello456hello"
//當replace方法的第二個參數是一個匿名函數的時候,正則比對了多少個内容,匿名函數就會被調用多少次。
var iNum = ;
var str = 'hello123hello456hello';
str.replace(reg, function () {
    console.log(arguments);
    //第一次列印: ["123", 5, "hello123hello456hello", callee: ƒ, Symbol(Symbol.iterator): ƒ]
    //第二次列印: ["456", 13, "hello123hello456hello", callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(`第${++iNum}次調用`) //列印出來了調用的次數
    return 'world'
    })
console.log(str) //"helloworldhelloworldhello"

           

類型檢測的四種方法

  • typeos

    :飯hide都是字元串,字元串對應的是資料類,例如:

    number

    ,

    string

    ,

    boolean

    ,

    undefined

    ,

    function

    ,

    object

    • 使用方法

      console.log(typeof 'a')

      //’string’
    • 局限性:

      console.log(typeof null)

      -> ‘object’;不能具體的細分是數組還是正則,還是對象中其他的值,因為使用typeof檢測對象類型資料,傳回的都是’object’
  • instance

    : 檢測某一個執行個體是否屬于某一個類
    • consle.log([] instanceof Array)

      -> true;
    • 局限性: 不能用來處理字面量方式建立出來的基本資料類型值
    • 對于基本資料類型來說,字面量方式建立出來的結果和執行個體方式建立出來的結果是有一定差別的,從嚴格的意義上來講,隻有執行個體建立出來的結果才是标準的對象資料類型值。也是标準的Number這個類的一個執行個體,對于字面量方式建立出來的結果是基本資料類型值,不是嚴謹的執行個體,但是由于js的松散特點,導緻了可以使用Number,prototype上提供的方法
    • console.log(1 instanceof Number)

      -> false;

      console.log(new Number(1) instanceof Number)

      -> true
    • instanceof

      的特性,隻要在目前執行個體的原型鍊上,我們用

      instanceof

      檢測出來的結果都是true。
  • construceor

    : 構造函數 作用和

    instanceof

    非常相似
    • console.log([].constructor === Array)

      -> true;

      console.log([].constructor === Regexp)

      -> false;
    • 可以處理基本資料類型的檢測;

      var num = 1; console.log(num.constructor === Number)

    • constructor

      檢測Object和instanceof不一樣,一般情況下是經檢測不了的

      console.log(/\d/.constructor === RegExp)

      -> true;

      console.log(/\d/.constructor === Object)

      -> false
    • 局限性:我們可以把類的原型鍊進行重寫,在重寫的過程中很有可能出現把之前constructor給覆寫了,這樣檢測的結果解釋不準确的
    • 對于特殊的資料類型null和undefined,他們的所屬類是Null和Undefined,但是被浏覽器保護起來了,不允許我們在外面通路使用。
//以下情況的改寫,會導緻constructor被覆寫
function Fn() {}
Fn.prototype = new Array;
var f = new Fn();
console.log(f.constructor) // Array()
           
  • Object.prototype.toString.call()

    相對前邊三個,最常用,最準确的資料類型檢測方式;
    • 思路:首先擷取Object原型上的toString方法,讓方法執行,并且改變方法中的this關鍵字的指向
    • 用法:

      var num = 1; console.log(Object.prototype.toString.call(num))

      -> ‘[object Number]’
  • toString的了解
    • 通常情況下是轉換為字元串,但是在某些toString方法不僅僅是轉換為字元串
    • 對于Number、String、Boolean、Array、RegExp、Date、Function原型鍊上的toString都是把目前的資料類型轉換為字元串的類型(他們的作用僅僅是用來轉換為字元串的)
    • Object.prototype.toString

      并不是用來轉換字元串的,他是傳回目前方式執行主體(this關鍵字)所屬類的詳細資訊
    • console.log((1).toString())

      //->number.Prototype.toString ->’1’ 轉換為字元串
    • console.log((1).__proto__.__proto__.toString())

      //-> Objcet.prototype.toString -> “[object Objcet]”
    • console.log((128).toString(2))

      -> 10000000 //轉換為二進制,參數可以是2,8,10…

繼續閱讀