JS經常使用知識點總結。(碼字ing)

JS的介紹

語言類型

  • HTML: 是一門超文本標記語言,「超文本」就是指頁面內能夠包含圖片、連接,甚至音樂、程序等非文字元素。
  • CSS : 層疊樣式表。CSS不只能夠靜態地修飾網頁,還能夠配合各類腳本語言動態地對網頁各元素進行格式化。
  • JS:JavaScript:是腳本語言,是基於對象的語言,是弱數據類型的語言,是基於事件驅動的語言,能夠寫業務邏輯

基於對象:就是說對象已經被定義好了,只須要用對象便可
弱數據類型:對數據類型不敏感,(java是強數據類型的語言)
基於事件驅動:即點擊,鍵盤等各類事件驅動
運行在瀏覽器:有瀏覽器便可。無需編譯:由瀏覽器直接解釋
通常用來給HTML網頁增長動態、交互、拖拽等功能。javascript

JS的基本組成部分

一、ECMAScript(ES):

ES是JavaScript的核心,描述了語言的基本語法(var、for、if、array等)和數據類型(數字、字符串、布爾、函數、對象(obj、[]、{}、null)、未定義)ECMAScript是一套標準,定義了一種語言(好比JS)是什麼樣子。css

二、文檔對象模型(DOM)

document object model文檔對象模型,裏面提供了元素屬性啥的,可讓咱們操做頁面中的元素操做DOM時,想操做誰,先獲取誰。
操做DOM的本質是=獲取(想操做誰就先獲取誰)+觸發(獲取後能夠綁定本身想要的事件)+改變(事件函數觸發後就能發生對應的改變)
html

DOM元素的獲取方式

一、直接經過元素的ID獲取 只支持高版本瀏覽器
二、經過getElementById('ID'), getElementsByTagName('標籤名'), getElementsByClassName('類的名稱')java

三、瀏覽器對象模型(BOM):

對瀏覽器窗口進行訪問和操做。這是瀏覽器裏默認的瞭解就行node

JS書寫的注意事項

  • script腳本推薦放在最下邊好處:防止因網絡問題,頁面加載時間長,出現空白;即使網絡問題,瀏覽器也把DOM加載渲染完成,等待從服務端下載完js腳本,出現效果
  • css不放在最下面緣由通俗地講:比如先穿好衣服在出去,瀏覽器先把css樣式準備好,在加載結構層,使得頁面有樣子;若是放在下面,由於頁面是從上往下加載,沒有css,就剩下裸露的標籤,很難看,使得用戶體驗很差
  • 綜上兩點所述故css腳本必須在script上面

JS的導入方式

  • 內嵌式 在頁面中直接寫入<script type="text/javascript">js代碼</script>。
  • 外鏈式 在頁面中引入外部文件<script src="xx.js"></script>。
  • 行內式 在標籤中(也就是元素裏)直接寫

<input type="button" value="點擊有驚喜" onclick="javascript:alert('哈哈哈哈')"/>ios

JS的輸出方式

  • console.log(js,cs,html);在控制檯輸出,能夠輸出一個或者多個,其間用逗號隔開
  • console.dir(js);在控制檯輸出詳細信息,用法同上
  • alert('hello world');在頁面上彈出helloworld
    • alert都是把要輸出的內容首先轉換爲字符串而後在輸出(調用了toString)
  • document.write("hello world"); 在頁面中直接顯示hello world
  • document.getElementById("search").value = "hello world" ;給id爲search這個文本框添加的內容
  • innerHTML/innerText ->給除了表單元素的標籤賦值內容
    • document.getElementById("div1").innerHTML = "吧啦吧啦吧啦吧啦";

JS中的常量及變量

變量命名規範

  • 由字母(a-zA-Z)數字(0-9)下劃線(_)以及美圓符號($)
  • 不能由數字開頭
  • 命名儘可能用英文而且具備必定的含義
  • 若是有多個英文單詞,後面單詞的首字母大寫(遵循駝峯式命名)
  • 不能使用關鍵字
  • 首字母不要大寫,大寫是有特殊含義的

常量

常量的值是不可變的,反之爲變量。常量用const定義ajax

變量(var,let)

JS數據類型的分類、檢測以及區別

數據類型

1、基本數據類型(值類型)

注意:基本數據類型是操做值的編程

一、數字類型

數字類型包括整數、小數、NANaxios

數據類型的轉換

注意:引用數據類型要轉爲數字類型,先轉爲字符串在轉爲數字類型(隱式轉換)
一、Number()將其餘數據類型轉化爲純數字類型,若沒有數字類型則返回NAN
二、parseInt()將其餘數據類型轉爲數字類型並取整,若沒有數字則返回NAN
三、parseFloat()將其餘數據類型轉爲數字類型並取小數點,若沒有數字則返回NAN設計模式

二、字符串

字符串的各類方法

全部字符串的方法都不會改變原字符串
一、字符串的拼接

  • 使用+號進行拼接 注意:只要數據兩邊有一邊是字符串就行
  • ES6用法,用反引號包住,變量須要用${}包住。例如:

二、獲取字符串中對應索引的數據

  • str[0] 獲取字符串str中第一個字符
  • str.charAt(0) 獲取字符串str中第一個字符

注意:以上二者的區別是當str中無此索引時,str[0]返回的是undefined,charAt[0]返回的是空字符串

  • str.charCodeAt(0) 獲取字符串對應索引字符的ASCII碼

三、字符串的轉換

  • str.toLocaleUpperCase() 將字符串轉爲大寫

  • str.toLoCaleLowerCase() 將字符串轉爲小寫

  • str.slice(n,m) 從索引n複製到索引m(可是不包括索引m)

  • str.substr(n,m) 從索引n獲取m個

  • str.split('+') 以指定的分割符,把字符串分割爲數組

    • 注意:這個返回值是數組。例如:'123'.split('2') 返回值['1','3']
  • str.replace('要被替代的字符','用來代替的字符') 替換

  • eval('str'):將字符串str當成有效的表達式來求值並返回計算結果。eval裏面必須是字符串,若是其餘數據類型想調用eval函數,則須要先轉化爲字符串再進行計算,例如eval(ary.jion('+'))返回值是改數組各項值相加的結果

三、布爾類型

  • Boolean() 將其餘數據類型轉化爲布爾類型,返回值只有ture或者false
    • 注意:'' , null ,NAN ,0,undefined 返回值都是false
  • 取反(!)取反的返回值也是布爾類型,其中有隱式轉換

2、引用數據類型(引用數據類型都是操做地址的)

一、數組

數組的建立
  • 字面量建立:var ary = [1,2]
  • 實例化-構建函數建立:var ary = new Array(1,2,3,4)
數組的增刪改查

一、原數組發生改變的方法

  • ary.push(1,2) 向數組的最後一項或者多項添加數據
  • ary.unshift(1,2) 向數組的最前面一項添加一項或者多項數據
  • ary.pop() 刪除數組中的最後一項
  • ary.shift() 刪除數組中最前面的一項
  • ary.length-1 刪除數字對應索引位置的數據
  • ary.splice()
    • 狀況一:splice(x) 只傳一個參數,表示從索引x開始刪除到末尾;
    • 狀況二:splice(x,y) 傳兩個參數,表示從索引x開始向後刪除y個
    • 狀況三: splice(x,y,z,f) 傳三個或者三個以上的參數時,表示從索引x日後刪除y項,並將第三位後面的參數替換刪除的地方

二、不改變原數組的方法

  • indexOf:查找數組中對應數據的索引值,若是沒有則返回-1。這是從左到右查找對應值;只要找到就會輸出結果;若是後面有重複的內容也不會輸出其索引值。廣泛用於數組的查重
  • lastIndexOf:查找數組中對應值的索引值;若是沒有返回-1;廣泛用於數組的查重;這是從右到左查找對應值;只要找到就會輸出結果;若是前面有重複的內容也不會輸出其索引值
  • ary.includes("x"):查找數組中是否有x這個數據;若是有返回結果ture;若是沒有返回false。能夠用來判斷數組中是否有這個數據
  • ary.slice() 返回值都是一個新的數組
    • 狀況一:ary.slice() 若是沒有傳參,則表示複製一份原有數組,返回值是一個新的數組
    • 狀況二:ary.slice(x) 只傳了一個參數,則表示從索引x開始一直複製到數組的末尾
    • 狀況三:ary.slice(x,y) 若傳了兩個參數,則表示從索引x開始日後複製y個
    • 狀況四:ary.slice(-x) 若傳了一個負數則表示從倒數的索引x開始日後複製
  • ary.sort():數組的自動排序,數字從0到9依次遞增,若是大於10,則會按照十位數的數接着排
  • 數字大於10時;且想用sort排序則能夠這樣用ary.sort(function(a,b){return a-b})當return裏的值是a-b時表示數組從小到大進行排序,如果b-a則表示從大到小排序
  • ary.resever():表示將數組倒序排列,返回的倒序數組和原數組相等
  • ary.concat()
    • ary.concat(x,y,z):表示將x,y,z拼接到數組裏,返回值是一個拼接好的新數組若是拼接的是數組則先將其拆開後再進行拼接
    • ary.concat():若沒有傳參則表示複製一份原有數組
  • ary.toString():表示將數組轉化爲新的字符串
  • ary.join():表示以指定分割符將數組轉化爲字符串。若沒有傳參則默認是逗號爲分割符
數組的去重
  1. 利用對象屬性名不能重複去重:先建立一個空數組和空對象,而後循環老數組,把老數組的每一項賦值給對象的屬性名,而後再循環對象;將對象中的屬性名添加到新數組中
let ary = [1,2,2,4,55,6];
let obj = {};
let arr = [];
function removeRep(ary){
    ary.forEach(item=>{
    obj[item] = 1
})
    for(var i in obj){
        arr.push(i*1)
        //由於對象的屬性名是字符串,要將其轉換爲數字再放進數組;
        //Number(K)也能夠換車給k*1 需求是同樣的
    }
    return arr
}
console.log(arr)//[1,2,4,6,55]
複製代碼
  1. 利用雙for循環,用數組的第一項和後邊的每一項進行比較,判斷他們是否相等,若是相等則刪除掉後邊的該項;並將後邊的索引往前減一位
let ary = [1,1,2,3,4,5,4]
function removeRep (ary){
    for(let i = 0 ; i<ary.length-1 ; i++){
        let before = ary[i]
        for(let k = i+1 ; k<ary.length ; k++){
            if(ary[i]===ary[k]){
                ary.splice(k,1);
                k = k-1
            }
            
        }
    }
    return ary
}
console.log(ary)//[1,2,3,4,5]
複製代碼
  1. 最簡單的方法就是利用indexOf去重,建立一個空數組,循環老數組,判斷新數組裏是否存在老數組的數據,若是沒有就將老數組的這一項添加到新數組中。
let ary = [1,2,3,4,5,7,11,5,2,1];
function removeRep(a){
    let arr = [];
    a.forEach(item=>{
        if(arr.indexOf(item)===-1){
            arr.push(item)
        }
    })
    return arr
}
removeRep(ary)
console.log(arr)//[1, 2, 3, 4, 5, 7, 11]
複製代碼

二、普通對象

普通對象;例如{屬性名:屬性值};普通對象是用大括號包住的。其中屬性值能夠時數字。而屬性名和屬性值成爲鍵值對,一個對象中可有多個鍵值對,多個鍵值對間用逗號隔開普通對象中的屬性名不能夠是數字加字母,但能夠是數字。且屬性名都是字符串,只是平時將其省略了

對象的方法
    • 打點的方式:obj.k
    • 中括號的方式:obj[Number]
  • 注意:以上兩種方式使用方法不一樣,其中打點的方式時,k不能是數字,而中括號的方式是適用於k是數字的時候
  • 改和增

改和增的方式和用法和上面一致,只須要直接賦值就能夠。例如:obj.name='hello';obj[2]=3

    • 假刪除:obj.name = null 賦值爲null只是假刪除,obj中仍是有這一項只是它的值爲null

而已

  • 真刪除:delete obj[k] 直接將obj中屬性名爲k的那一項刪除

三、函數

一、函數的應用
  • 回調函數:回調函數就是一個函數以參數的形式傳給另外一個參數執行。
function fn(num1 , num2 , callback){
    return callback(num1 , num2)
}
function fn2(num3 , num4){
    return num3 + num 4
}
fn(1,2,)
複製代碼
  • 遞歸函數:遞歸函數是回調函數的特殊例子,遞歸函數是本身調用本身,使用遞歸函數時必需要設置邊界點,不然會陷入死循環。通常用於求和。
let num = 0;
function sum(n){
    if(n<5){
        num = n + sum(n+1) 
    }
    return num
}
sum(1)
console.log(num) //10
複製代碼
  • 不定項求和:求0到100累加求和
let total = 0;
function sum(num){
   
    for(let i = 0 ; i<num+1 ; i++){
        total += i
    }
    return total
}
sum(100)
console.log(total) // 5050
複製代碼
  • 使用遞歸求和
let total = 0
function sum(num){
    if(num<101){
        total = num + sum(num+1)
    }
    return total
}
sum(0)
console.log(total) // 5050
複製代碼
  • 利用函數模擬驗證碼
function getNum(n){
    let str = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890';
    let str2 = '';
    function num(n){
        n = n || 4;
        let ary = [];
        while(ary.length<n){
            let index = Math.round(Math.random()*61);
            if(ary.indexOf(index)==-1){
                ary.push(index)
            }
            
        } 
        return ary
    }
    function getCode(n){
        n = n || 4;
        num(n)
        ary.forEach(item=>{
            str2 += str[item] 
        })
    }
     getCode(n)
    return str2
}
consloe.log(getNum(5))
複製代碼
  • 奇偶行變色
<body>
    <ul>
        <li>1<li>
        <li>2<li>
        <li>3<li>
        <li>4<li>
    </ul>
</body>

<script>
    let lis = document.getElementByTagName('li');
    for(let i = 0 ; i<lis.length ; i++){
        if(i%2===0){
            lis.style.backgound = 'red'
        }else{
            lis.style.background = 'green'
        }
    }
</script>
複製代碼

四、Math

Math的各類方法
  • Math.abc():取絕對值
  • Math.ceil():向上取整
  • Math.foolr():向下取整
  • Math.round():四捨五入
  • Math.random():取0到1中間的隨機小數(不包括1)
    • 取隨機數
      function sum(m,n){
          return Math.floor(Math.random()*(m-n)+n)
      }
      sum(1,100)
      複製代碼
  • Math.max():取其中數字的最大值
  • Math.min():取其中數字的最小值
  • Math.PI:獲取圓周率
  • Math.pow(x,y):x的y次方
  • Math.sqrt(x,y):x開y次方

五、Date(日期)

日期的各類方法
  • new Date():獲取本機此刻時間
  • new Date().getFullYear():獲取本年份
  • new Date().gerMonth():獲取本月份;注意:它的月份中是0到11,0爲我們的1月份
  • new Date().getDay():獲取星期幾;注意:它的星期也是0到6;同上
  • new Date().getData():獲取日期
  • new Date().getHours():獲取當前的小時
  • new Date().getMinutes():獲取當前分鐘數
  • new Date().getSeconds():獲取當前秒數
  • new Date().getTime():獲得如今時間減去1970年1月1日0時0分0秒的毫秒數

JS中數據類型的檢測

  • typeOf():檢測該數據類型。typeof()能夠準確的判斷基本數據類型,可是不能判斷引用數據類型;返回值都是字符串的形式;注意:null返回的是object;NAN返回的是number。
console.log(typeof('你好'))// 'string';
console.log(typeof(null))  // 'object';
console.log(typeof(undefined)) //'undefined';
console.log(typeof(5)) //'number';
console.log(typeof(Function)) //'function'
console.log(typeof(false)) //'boolean'
console.log(typeof(NaN)) //'number'
複製代碼
  • instanceof():判斷已知數據類型的方法;注意:這個只能判斷引用數據類型,如果值類型則返回的都是false。原理是獲取當前實例在原型鏈中是否在原型上。
console.log([] instanceof Array) // true
console.log(function fn(){} instanceof Function) // true
console.log({} instanceof Object) // true
複製代碼
  • constructor:獲取當前實例的構造器
console.log([].constructor) // f Array{} [native code]
console.log({}.constructor) // f Object{} [native code]

複製代碼
  • Object.prototype.toString.call()精確判斷對象類型。
console.log(Object.prototype.toString.call(5)) // [object Number];
console.log(Object.prototype.toString.call(null)) // [object Null];
console.log(Object.prototype.toString.call(NAN)) // [object Number];
console.log(Object.prototype.toString.call('')) // [object String];
複製代碼

堆棧內存和垃圾回收詳解

  • 內存中分動態存儲區(棧內存、堆內存)、靜態存儲區、程序代碼區
    • 堆棧內存的區別
      1. 從存放內容空間上看:
      • 棧內存的內存空間要遠遠小於堆內存,主要是存放對象的地址、基本數據類型。因爲內存很小,使用死循環會出現內存泄露。而內存泄露的結果就是內存溢出。
      • 堆內存的空間要大一些,主要用於引用數據類型。
      • 內存泄露:一直往內存裏面存儲內容,而不進行清理。(例如死循環)
      • 內存(堆棧)溢出:當存儲的數據達到必定的限制時,就會形成內存(堆棧)溢出。
  • 垃圾回收
    • 基本數據類型在當前環境執行完後會自動銷燬,而引用數據類型不會。因此就有了垃圾回收機制。
    • 垃圾回收是將對象的變量賦值爲null,而且沒有其餘變量引用這個對象的地址,系統就會將他清理。可是不會及時清除,垃圾回收車會根據內存的狀況在適當的時候清除堆中的孤兒對象。(沒有被引用的對象就是孤兒對象)

js做用域

  • 做用域:用於存儲和訪問變量;換句話說就是變量的可訪問範圍。
  • 全局做用域、塊級做用域
    • 全局做用域:所存儲的變量在全局均可以訪問;在函數外定義的變量和函數內直接賦值的變量都是在全局做用域內。
    • 局部做用域:變量在代碼的局部片斷才能夠訪問;常見的有函數做用域以及塊級做用域。函數的形參也是局部變量。
      • 函數做用域:在函數內部聲明的變量在函數做用域內,只有在函數裏面的代碼才能夠訪問。
      • 塊級做用域:在{}中使用let和const聲明變量就會造成塊級做用域。

做用域鏈

  • 做用域鏈是查找變量的一種機制;在查找變量時會一級一級向上查找;直到找到所需的變量。若是找不到就宣佈放棄,代碼報錯。

賦值以及深淺拷貝的淺析

賦值與淺拷貝的區別

  • 賦值是將某一數值或者對象賦給變量;當賦值的僅僅是一個基本類型時,a與b互不影響;可是賦值是一個對象時,a與b屬於同一地址,改變其中的任何數據都會相互影響。
    • 將a對象賦值給b時
    let a1 = 2;
    let b2 = a1;
    b2 = 10
    console.log(a1) //2
    let a = {
        name:'小可愛',
        obj:{
            age:20
        }
    }
    let b = a
    b.name = '大可愛'
    console.log(a) //{name:'大可愛',obj:age:20}
    複製代碼

深淺拷貝的區別

  • 深淺拷貝只是針對object和array這樣的引用數據類型。
    • 淺拷貝只是複製指向某個對象的指針,而不是複製對象自己,新舊對象仍是共享同一塊內存。淺拷貝在改變最外層的基本數據類型時,原對象不會改變,可是若是改變對象下的引用數據類型,原對象也會發生改變。
    • 深拷貝則會另外創造一個一摸同樣的對象,新舊對象不共享內存,修改新對象不會影響舊對象。
  • 常見的淺拷貝
    • Object.assign(),合併對象
    let a = {
        name:'小可愛',
        obj:{
            age:20
        }
    };
    let b = {
        name:'乖乖',
        b:2
    }
    let target = {}
    Object.assign(traget,a,b)
    console.log(traget)//{name:'乖乖',b:2,age:20}
    target.b = 20;
    console.log(b)//{name:'乖乖',b:2}
    target.obj.age = 30
    console.log(a)//{name:'小可愛',obj:{age:30}}
    
    複製代碼
    • 展開語法Spread syntax
    let a = {
        name:'小可愛',
        obj:{
            age:20
        }
    };
    let target = {...a};
    target.name = '糟老頭';
    target.obj.age = 10;
    console.log(a)//{name:'小可愛',obj:{age:10}}
    複製代碼
    • splice複製
    let a = ['小可愛',{age:20}];
    let target = a.slice();
    target[0] = '糟老頭';
    target[1].age = 30;
    console.log(a)//['小可愛',{age:30}]
    複製代碼
  • 常見的深拷貝
    • JOSN.parse(JSON.stringify):用JOSN.stringify()將對象轉爲JOSN字符串;再用JOSN.parse()把字符串解析爲對象,一來一去會產生新的對象,實現深拷貝;這種方法雖然能夠實現對象和數據的深拷貝,可是不能處理函數。這是由於JOSN.stringify()方法是將js值(數組或者對象)轉換成JSON字符串,不能接收函數。
    let ary = [1,{age:10}];
    let arr = JOSN.parse(JSON.stringify(ary));
    arr[2].age = 20
    console.log(ary)//[1,{age:10}];
    let obj = {age:2,name:'小可愛'};
    let obj2 = JSON.parse(JSON.stringify(obj));
    obj2.name = '糟老頭子';
    console.log(obj)//{age:2,name:'小可愛'};
    //JSON.stringify(),將普通對象轉化爲JSON字符串,被轉化的參數必須是對象。
    //注意:JSON.prase(),轉化的對象必須是JSON字符串,他的做用是將JSON字符串轉化爲JSON對象
    複製代碼
  • jQery.extend()合併多個對象

原型/構造函數/實例

  • 原型:基本數據類型沒有原型,只有引用數據類型有原型。數組的原型是Array.prototype、對象的原型是Object.prototype、函數的原型是Function.prototype、而他們的原型的原型指向基類Oject的原型,最終的原型就是基類Object,萬物皆對象就是這麼來的。原型的做用是存儲一些公共的方法和屬性供實例使用。
    • 全部的函數都有一個prototype屬性,其屬性值都是一個對象,每個對像都有一個__proto__屬性;這個屬性值爲指向當前所屬類的原型。

實例、原型、構造器函數三者的關係

  • 實例.proto === 原型
  • 原型.contructor === 構造函數
  • 構造函數的.prototype === 原型
  • 實例.constructor === 構造函數

原型鏈定義以及它的做用

  • 原型鏈:原型鏈是由原型對象組成的,每一個對象都有__proto__屬性,執行了該對象的的構造器的原型;__proto__將對象連接起來,組成原型鏈。
  • 原型鏈的做用:
    • 屬性的查找機制:當查找對象的屬性時,當前實例如若沒有則經過原型鏈向上一級查找,找到則輸出,找不到則輸出undefined。
    • 屬性的改變機制:若是須要在原型上添加或者修改屬性時,能夠經過b.prototype.x = 123;其中B是構造函數。
    • 兩道題助你更加理解原型鏈
    //第一題
    function F(){};
    function O(){};//原型是對象
    O.prototype = new F(); //O如今原型是對象
    let obj = new O(); //obj是O的實例,原型是Obj.prototype
    console.log(obj instanceof O) //true  obj在O的原型鏈上
    console.log(obj instanceof F) //true  obj也在F的原型鏈上
    obj.__proto__ == O.prototype  //true
    obj.__proto__.__proto__ === F.prototype //true
    //第二題
    function F(){};
    function O(){}; // O的原型是對象
    let obj = new O() // 
    O.prototype = new F()
    console.log(obj instanceof O) //false
    console.log(obj instanceof F)//false
    console.log(obj.__proto__ === obj.prototype) //false
    複製代碼

閉包

  • 閉包函數:聲明在函數內部的函數叫作閉包函數
  • 閉包:內部的函數能夠訪問其所在外部函數聲明的參數和變量。

閉包的特色

  • 優勢:
    • 避免使用全局變量,保護全局變量被污染
    • 讓外部函數能夠訪問到內部變量
  • 缺點:
    • 局部變量會常駐在內存中
    • 致使內存泄漏,內存長期被佔用,而不被釋放。解決內存泄漏的問題,在退出函數前,刪除掉不用的局部變量。

閉包的建立

  • 每次外部函數執行的時候,外部函數的引用地址不一樣,都會從新建立一個新的地址

new運算符執行的時候都發生了什麼

  • 先建立一個對象,這個對象繼承了該構造函數的原型
  • 執行構造函數,並將this指針指向新對象
  • 返回新對象
let new1 = function(foo){
    let obj1 = Object.create(foo.prototype)//建立一個新對象,這個對象繼承了foo構造器的原型
    let obj2 = foo.call(obj1)//執行foo,並把this指針指向obj1;new建立一個實例時;實例的this
    //指向它自己。這裏的obj2返回的時[],由於Array()執行了
    if(obj2 === 'object'){
        return obj2
    }else{
        return obj1
    }
}
new1(Array)
複製代碼
  • 使用new來調用構造函數時,若是return的是一個非對象(數字、字符串、布爾類型、null等)會忽略返回值;若是return的是一個對象,則會返回該對象。下面兩道題帶你理解new。
//第一題
function Person(name){
    this.name = name;
    return name
}
let p = new Peron('tom');//Person{name:tom}

// 第二題
function Person(name){
    this.name = name;
    return {}
}
let p = new Person('tom');//{} 
複製代碼

模塊化

  • 模塊化開發大大提升了項目的可維護性,可拓展性和可協做性;一般咱們在瀏覽器中使用ES6的模塊支持;在node中使用common.js的模塊支持。
  • ES6
    • import 導入
    • export 導出
  • common.js
    • require 導入
    • exports 導出
    • module.exports 導出
  • require和import的區別
    • require支持動態導入,import不支持
    • require 是同步導入,import是異步導入
    • require是值拷貝,導出值變化不會影響導入值,import是指向內存地址,導入值會隨着導出值變化而變化

防抖和節流

防抖

  • 防抖的做用:將屢次高頻的操做優化爲最後一次執行,使用場景是:用戶輸入。只需在輸入完成後,進行校驗。
  • 節流:每隔一段時間執行,將高頻轉化爲低頻。使用場景:短信驗證60s後重發,滾動條事件等等。

定時器的區別

  • setTimeout:指定毫秒數後,執行內部函數,只執行一次,定時器執行完後timer爲1;若是有兩個爲2
    • let timer = setTimeout(()=>{},2000)
  • setInterval:按毫秒數,每毫秒數執行一次內部函數,直至clearInterval

this的做用以及改變this的方法和差異

  • this的做用:
    • js的設計原理:在函數中能夠引用運行環境的變量。所以就須要一個機制來讓咱們在函數體內部獲取當前的運行環境。而這個機制就是this。
    • 運行環境指的就是函數被誰調用,而誰就是this。
  • 判斷this的指向
    • obj.fn(),這裏的fn裏的this指的就是obj,fn2()的主體就是window,fn2()函數中this指的就是window。
    • 自執行函數的this都是指向window。
    • 給元素綁定事件,當事件觸發時,綁定方法裏的this執行這個元素。
    function fn(){
        console.log(this) 
    }
    docoment.getElementById('div').onclick = function(){
        console.log(this)//div
        fn() //window
    }
    document.getElementById('div').onclick = fn;//div
    複製代碼
  • 改變this指向的方法。
    • fn.call(obj,1,2,3);將fn的this指向obj,傳參爲1,2,3參數列表,並當即執行函數fn。
    • fn.apply(obj,[1,2]);將fn的this指向obj,傳參爲1,2;apply的傳參格式爲數組,當即執行函數fn
    • let call = fn.bind(obj,1,2);call返回一個函數體,函數須要時調用;調用call執行後4後,將fn的this指向obj,傳參爲1,2。
  • call、apply、bind的區別:
    • call和apply都是當即執行,只是call傳參是參數列表的格式,apply是數組。
    • call和bind的參數傳參格式是同樣的,只是bind不是當即執行。

手寫實現call,apply,bind

  1. 手寫call
Function.prototype.newCall = function(arg){
	let ctx = arg || window;
    ctx.fn = this;
    let params = [...arguments].slice(1);
    let res = ctx.fn(...params);
    delete ctx.fn
    return res
}
let obj = {
	name:'你好',
    fn:function(...arg){
    console.log(this.name,...arg)
    }
}
obj.fn.newCall(obj,'年齡22','體重25Kg')
複製代碼

2.手寫apply

Function.prototype.newApply = function (context, arg) {
        let ctx = context || window;
        ctx.fn = this;
        let res = ctx.fn(...arg);
        delete ctx.fn
        return res
    }
    let obj = {
        name: '你好',
        fn: function (...arg) {
            console.log(this.name, ...arg)
        }
    }
    obj.fn.newApply(obj, ['年齡22', '體重25kg'])
複製代碼

3.手寫bind

Function.prototype.newBind = function (context=window){
	let ctx = context;
    ctx.fn = this;
    let arg = [...arguments].slice(1);
    return function(){
    	ctx.fn(...arg)
    }
}
let obj = {
        name: '你好',
        fn: function (...arg) {
            console.log(this.name, ...arg)
        }
    }
複製代碼

ES6基礎知識

變量提高

  • 變量提高:該變量還未被聲明,在代碼執行以前,先在詞法環境種進行註冊。若是變量聲明的是一個全局變量就會將變量聲明提高到全局做用域頂部。若是變量的聲明是在函數裏,則將變量提高到函數做用域的開頭。
    • 變量的提高:var既聲明一個變量又定義;只有var有變量提高;let和const沒有變量提高。
    • 函數的提高:函數既聲明也定義。函數的聲明優先級高於變量。

let const var三者的區別

  • var存在變量提高;let和const不會。
  • var聲明的全局變量會掛載到window上,let和const不會。
  • 在{}用let和const聲明的變量會產生塊級做用域,var不會。
  • let和const聲明的變量不能再進行聲明,可是能夠修改。不存在暫時性死區(在{}內使用let或者const就會產生塊級做用域,他所聲明的變量在這個區域內在它以前使用都會報錯)
var sun = 1;
if(true){
    sun = 1;//報錯;
    let sun = 2;
}
複製代碼

map、filter、reduce、forEach

  • forEach和map的區別:forEach沒有返回值;map有返回值;並且必須用return返回,不然外界拿不到。
    • forEach例子;forEach第一個參數爲element,第二個參數時index,第三個參數是原數組
    let ary = [1,2,3];
    let sum = 0;
    ary.forEach((item,index,arr)=>{
        sum += item //6
        console.log(index) //0,1,2
        console.log(arr) // [1,2,3]
    })
    複製代碼
    • map例子;map第一個參數爲element,第二個參數時index,第三個參數是原數組
    let ary = [1,2,3];
    let ary = ary.forEach((item,index,arr)=>{
        return item*2
    })
    console.log(ary)//[2,4,6]
    複製代碼
  • filter的做用是用來過濾(篩選),返回的是一個新數組。傳入的函數返回值爲true就放入新數組,爲false不放入新數組。
    • 例子以下:
    let ary = [1,2,3];
    let arr = ary.filter((item,index,arr2)=>{
        return item>2
    }) 
    console.log(arr)//[3]
    複製代碼
  • reduce能夠將數組的元素經過回調函數最終轉爲一個值,經常使用於求和。
    • 例子以下:
    let ary = [1,2,3];
    let sums = ary.reduce((sum,element,index,arr)=>{
        //sum 上一次的累加值;elememt當前元素;index當前元素索引;arr原數組
        return sum + element
    })
    console.log(sums)//6
    複製代碼

解構賦值

  • 解構賦值語法是JS的一種表達式,經過解構賦值能夠將屬性或者值從對象或者數組中取出,賦值給其餘變量。

解構賦值語法

  • 解構數組
let ary = ['one','two','three'];
let [a,b,c] = ary;
console.log(a,b,c);// 'once','two','three'
複製代碼
  • 默認值
    • 爲了不從數組中拿到undefined,咱們能夠給變量設置一個默認值
    let a,b;
    [a = 2,b = 3] = [1,2];
    console.log(a,b);//1,2
    複製代碼
  • 交互變量
    • ES6解構賦值時,每句話結束必須加分號,不然有些地方會報錯。
    let [a,b] = [1,2];
    [b,a] = [a,b]
    console.log([a,b]) //2,1
    複製代碼
  • 解析從函數中返回的數組
function fn(){
    return [1,3]
};
[a,b] = fn();
console.log(a,b);//1,3
複製代碼
  • 忽略某些值,用,表示忽略的值。一個逗號表明一個值。
let ary =  [1,2,3,4];
[a,,b] = ary;
console.log(a,b)//1,3
複製代碼
  • 利用展開運算符將剩餘的值賦值給一個變量
let ary = [1,2,3,4];
[a,...b] = ary;
console.log(a,b)//1,[2,3,4]
複製代碼
  • 解構對象
    • 解構對象時須要注意,若是須要賦值給新的變量名則須要將屬性和屬性值寫出來
    let obj = {key:1,all:2};
    let {key:num1,all:num2} = obj;
    console.log(num1,num2);//1,2
    複製代碼
    • 若是賦值的變量名不變則能夠只寫變量名
    let obj = {key:1,all:2};
    let {key,all} = obj;
    console.log(key,all);//1,2
    複製代碼
    • 無聲明解構對象時,須要用()包住,不然報錯
    let obj = { key : 1 , all : 2};
    ({key,all} = obj);
    console.log(key,all)
    複製代碼

箭頭函數和普通函數的區別。

  • 箭頭函數是匿名函數,不能用new執行。
  • 箭頭函數的this是指向上級做用域的this。
let obj = {
    a:()=>{
        console.log(this)
    }
}
obj.a() //window;由於obj的this是window
複製代碼
  • 箭頭函數沒有arguments
  • 箭頭函數沒有原型屬性
let obj = {
    a:()=>{
        console.log(this)
    }
}
console.log(obj.a.prototype)//undefined
複製代碼
  • 箭頭函數不能改變this指向。

Class類的聲明和繼承

  • 聲明類
class Obj {
    constructor(x,y){
        //this是obj類的實例;這些屬性是私有屬性
        this.x = x;
        this.y = y;
    },
    to(){
        return this.x+this.y
    }
}
let obj = new Obj(1,2);
console.log(obj); {x:1,y:2}
obj.to()//3
複製代碼
  • 類的繼承
class Obj {
    constructor(x,y){
        //this是obj類的實例;這些屬性是私有屬性
        this.x = x;
        this.y = y;
    },
    to(){
        return this.x+this.y
    }
}
class Arr extends Obj {
    constructor(a){
        super(2,3)
        this.c = a
    }
    fn(){
        return this.x+this.y+this.c
    }
}
let arr = new Arr(5)
console.log(arr){x:2,y:3,c:5}
arr.fn()//8
複製代碼

Promise的使用和實現

  • promise是解決回調地獄的。回調地獄指的是多層回調嵌套,致使代碼很難閱讀。
function fn(num1,num2){
    return new Promise((resolve,reject)=>{
        let sum = num1 + num2;
        resolve([sum,num1])
    })
}
fn(1,2).then(([sum,num1])=>{
    console.log(sum,num1) //3,1
    return sum
}).then((num)=>{
    console.log(num+5) //8
})
複製代碼
  • promise中的resolve只能接收一個參數,若是須要傳多個參數,則須要用數組或者對象進行傳參。

Array.from()的理解

  • Array.from()是將類數組對象或者是可遍歷的對象或者字符串轉爲一個真正的數組。
  • Array.from()的使用方法
    • 將字符串轉爲數組
    let str = 'abc'
    let arr = Array.from(str)
    console.log(str)//['a','b','c']
    複製代碼
    • 利用Set類數組結合Array.from()實現數組的去重
    let ary = [1,1,2,4,5,4,5,6,7];
    let set = new Set(ary);
    let a = Array.from(set)
    console.log(a)//[1,2,4,5,6,7]
    複製代碼
    • 將一年的銷售額存在一個對象裏,將其處理爲數組
    let obj = {1:220,2:300,5:400}
    let result = Array.from({length:5},(item,index)=>{
    		return obj[index+1] || null
    })
    console.log(result)//[220,300,null,null,400]
    //必須有item,不然返回的數組都是null
    複製代碼

什麼叫回調函數?回調函數有什麼優勢。

  • 回調函數的定義:回調函數就是一個函數做爲另外一個函數的參數,這個參數的就是回調函數。
function callback(num1,num2,back){
    let sum = num1+num2;
    back(sum)
}
function print(num){
    console.log(num)
}
callback(1,2,print)

//用promise實現
function fn(num1,num2){
    return new Promise((resolve,reject)=>{
        let sum = num1+num2
        resolve(sum)
    })
}
fn(1,2).then((sum)=>{
    console.log(sum)
})
複製代碼
  • 例如axios請求和點擊事件中就使用了回調函數
  • 回調函數的優勢:
    • 回調函數不會馬上執行,回調函數和普通的函數同樣,在須要用到的地方調用纔會執行。
    • 回調函數是個閉包。它能夠訪問到其外層定義的變量。

發佈訂閱設計模式

  • 發佈訂閱指的是發佈函數和訂閱函數。
    • 訂閱函數:將須要發佈的函數放入是事件池中。
    • 發佈函數:發佈的時候執行相應的回調。
  • 應用場景
    • js在dom元素綁定事件。訂閱就是在dom元素綁定事件,發佈就是點擊時執行回調函數。

面向對象(oop)和麪向過程(opp)

  • 面向過程就是分析出解決問題所須要的步驟,而後用函數把這些步驟一步一步的實現。使用的時候再一一調用就行。
  • 面向對象:面向對象就是把須要解決的問題都歸類,拿蛋炒飯來比喻的話就是飯是一個對象,蛋是另外一個對象,我們能夠先炒蛋在炒飯,最後把蛋倒在飯上,若是用面向過程就是把蛋和飯放到一塊兒翻炒。
  • 面向對象和麪向過程的優缺點。
    • 面向對象的耦合度低,可維護性高,易複用。面向過程的性能高。

  • 對象通常是由屬性和方法組成,屬性用來描述某個對象的靜態特徵,方法是用來描述對象的動態特徵.對象是類的一個實例化,好比小明和小紅都是人類,他們都是人類的實例化。

js繼承

  • 原型繼承
    • 子類.prototype = new 父類
    • 子類.prototype.constructor = 子類
    • 原型繼承的特色:會將父類的私有屬性和公有屬性完成繼承到子類的公有屬性
    function Father(){
        this.x = 2;//私有屬性
        this.method = function(){
            console.log(this.x)
        }
    }
    Father.prototype.pub = 5 //公有屬性
    function Son(){
        this.a = 4
    }
    Son.prototype = new Father
    Son.prototype.constructor = Son
    
    let son = new Son()
    console.log(son)  //{a:4}=>__proto__=>Father=>{x:5}
    複製代碼
  • 借用構造函數
    • 在子類的構造函數中,經過call方法調用父類函數,看成一個普通函數執行,並將父類的this(運行環境)指向子類。這樣就至關於將父類的私有屬性複製一份到子類的實例中。
    • 特色:只了父類的私有屬性,做爲本身的私有屬性。
    function Father(){
       this.x = 2;//私有屬性
       this.method = function(){
            console.log(this.x)
        }
    }
    Father.prototype.pub = 5 //公有屬性
    function Son(){
        Father.call(this)//將父類的函數看成一個普通函數執行
    }
    複製代碼
  • 寄生組合
    • 公有繼承公有,私有繼承私有
    function Father(){
        this.x = 2;
        this.method = function(){
            console.log(this.x)
        }
    };
    Father.prototype.pub = 5;
    //繼承公有屬性
    Son.prototype = Object.create(Father);//建立一個新對象,這個對象的原型指向Father.prototype
    Son.prototypr.constructor = Son;
    function Son(){
        Father.call(this);//將Father的私有屬性賦給Son的私有
    }
    let son = new Son()
    複製代碼

js中的事件循環(代碼執行順序)

  • js是單線程,因此任務只能一個一個的去執行。當咱們打開網頁時,網頁的渲染和dom解析就是同步任務,而加載圖片、音樂等大量的下載任務就是異步任務。
  • 事件循環的順序
  1. 任務進入執行棧
  2. 判斷任務是同步仍是異步。
  3. 同步進入主線程;異步進入Event table,註冊函數等待被調用,並將函數移入Event Queue(事件隊列)。
  4. 當js引擎檢測到主線程執行棧爲空時,開始執行異步,js引擎去Event Queue 中執行宏任務。宏任務執行完後,看看是否有同級的微任務,如如有執行微任務,執行完微任務再進入下一個宏任務,這就是事件循環。
  • 宏任務有:setTimeout、setInterval
  • 微任務有:promise;注意:promise.then屬於微任務,若是是new Promise則是當即執行函數,不是微任務。process.nextTick()定義讓代碼再下個時間點執行,在同級的宏任務執行完後、ajax、axios

事件

事件流

HTML中與js的交互是經過事件來實現的,例如點擊事件、頁面滾動事件onscroll。

什麼是事件流:事件流指的是從頁面中接收事件的順序。 事件流的順序是先捕獲後冒泡。

事件流有下面幾個階段:

  • 事件捕獲階段
  • 處於目標階段
  • 事件冒泡階段

阻止事件

  • 事件冒泡是默認的,因此阻止事件冒泡的方法是e.stopPropagation()
  • 阻止事件捕獲e.stopImmediatePropagation()
  • 阻止默認事件e.preventDefault()

事件的監聽

e.addEventListener(event,function,useCapture)方法,用於向指定元素添加事件,他能夠更簡單的控制事件的觸發階段。

  • 第一個參數指的是定義的事件,例如click、mousedown
  • 第二個參數是事件觸發後的執行函數
  • 第三個參數指的是事件觸發的階段
    • true 事件在捕獲階段觸發
    • false 事件在冒泡階段觸發

經常使用的事件

鼠標事件

  • onclick 點擊事件
  • ondbclick 雙擊事件
  • onmouseover 鼠標移入
  • onmouseout 鼠標移出
  • onmousedown 鼠標按下
  • onmouseup 鼠標擡起
  • onmousemove 鼠標移動
  • onwheel 鼠標滾動
  • oncontextmenu 點擊鼠標右鍵

鍵盤事件

  • onkeydown 按下鍵盤
  • onkeyup 擡起鍵盤

表單事件

  • onfocus 元素獲取焦點
  • onblur 元素失去焦點
  • onchange 元素內容改變
  • oninput 元素獲取用戶輸入內容
  • onsubmit 提交按鈕時觸發

拖動事件

  • ondrag 元素正在拖動時觸發
  • ondragend 元素結束拖動時觸發

框架/對象事件

  • onresize 瀏覽器窗口
  • onload 元素加載完成
  • onscroll 元素滾動時觸發
  • onunload 用戶退出登陸頁面時觸發

事件委託(事件代理)

事件委託就是利用事件冒泡,大大的提升了性能優化。在須要觸發事件的父元素上設計函數監聽,父元素經過監聽子元素上觸發的事件來觸發事件。最經典就是ul下的li。

好處:比較適合動態元素的綁定,新增長的新元素也會有監聽函數。也能夠有事件觸發機制。

Ajax

實現一個Ajax

let xhr = new XMLHttpRequest() //建立一個ajax對象
//必須在open()以前指定onreadystatechange 事件處理程序才能保證跨瀏覽器的兼容性 xhr.onreadystatechange = function(){
if (xhr.readystate === 4 ){
if(xhr.state === 200 && xhr.state < 300 || xhr.state === 304){
console.log(xhr.responseText) }else{
console.log('Error'+ xhr.status)
}
xhr.open('get','url',true) // 第三個參數true表明異步,若是是false表明是同步
xhr.send(data) // 參數做爲請求主體發送的數據 }}

js盒子模型

  • client獲取當前元素可視區域的寬高
    • clientHeight = height + 上下paddiing
    • clientWidth = width + 左右padding
    • clientTop = 上border邊框的寬度
    • clientLeft = 左border邊框的寬度
  • offset獲取

圖片懶加載

window.onLoad和DOMContentLoaded事件的前後順序

  • window.onload:在頁面載入完成的時候執行。
  • DOMContentLoaded:在DOM樹構建完成時執行。
    • 觸發形式document.addEventListenner(DOMContenLoaded,function(){},flase)
  • 執行順序:DOMContentLoaded先執行,window.load後執行。

js中處理異步的方法有哪些

  1. 回調函數
function callback(fn){
    setTimeout(()=>{
        fn()
    },100)
}
function fn2(){
    console.log(11)
}
callback(fn2)
複製代碼
  1. 發佈訂閱;簡單的例子就是在元素上綁定點擊事件,點擊元素後觸發響應的函數。
  2. promise
function p(num1,num2){
    return new Promise((resolve,rejece)=>{
        setTimeout(()=>{
            let sum = num1 + num2
            resolve(sum)
        },100)
    })
};
p(1,2).then(sum=>{
    console.log(sum)
})
複製代碼
  1. Generator函數(演變爲async和await語法)
    • 建立一個generator函數的方法,在function關鍵字與函數名之間加一個*;二是函數體內部用yield,定義內部不一樣的狀態。
    • 調用函數,函數不會當即執行,會返回一個遍歷器對象,須要調用next()方法,函數纔會執行。next()會返回一個對象,對象中有value表示yield或者return的值,done表示函數 是否執行結束,若是結束返回的則是done:true;以後的每一次next都是從上一次yield開始。
    function* gen(){
        let res = yield 'hello';
        yield res;
        return '你好';
    }
    let g = gen() 
    console.log(g.next())//{value:"hello",done:false};
    conso.log(g.next(20))//{value:20,done:false}//在next中傳入的參數會做爲上次yield的返回值
    console.log(g.next())//{value:'你好',done:true}
    複製代碼
    • 可是如何使用generator函數來進行異步編程呢;這裏使用ES2017中的async和await語法(其實屬於generator函數的語法糖)
    • 使用async代替函數後的*,await代替yield就將generator改形成一個async函數。
    function fnA(n){
        return new Promise(resolve=>{
            //異步操做
            resolve(n)
        })
    }
     function fnB(n){
        return new Promise(resolve=>{
            //異步操做
            resolve(n)
        })
    }
    
    async function gen(){
        let resA = await fnA(1)
        let resB = await fnB(resA)
    }
    gen()
    複製代碼
  • async和await的詳解
    • await只能放在async裏面
    • await後面通常跟return new Promise
    • 最好把await和成功後的操做放到try中,失敗的放在catch中。
      function getNum(n){
          return new Promise((resolve,reject)=>{
              let sino = parseInt(Math.random()*6+)
              if(sino>3){
                  if(n=="大"){
                      resolve(sino)
                  }else{
                      reject(sino)
                  }
              }else{
                  if(n == '大'){
                      reject(sino)
                  }else{
                      resolve(sino)
                  }
              }
          })
      }
      async function test(n){
          try{
              let num = await getNum(n)
              console.log('贏了',num)
          }catch(error){
              console.log('輸了',error)//這裏error接收的是reject的值
          }
      }
      test('大')
      console.log(test('大'))//返回的是一個Promise對象。
      複製代碼
      • async函數的返回值是一個Promise對象,並且這個對象的狀態是resolve的,若是沒有寫return,則resolve的值是undefined,若是寫了這個返回值就是resolve的值。
      • 特別注意,await後面的promise函數若是沒有resolve值,對await來講就算失敗了,下面的代碼會執行
      function fn(){
        return new Promise(resolve=>{
        console.log(1)
        //resolve
        })
      }
      async function f1(){
        await fn()
        console.log(2)
      }
      f1()
      console.log(3)
      //1,3
      //若是有resolve,1,3,2
      複製代碼
  • async await和promise哪一個更好。
    • promise經過.then鏈來解決多層回調的問題,寫法較爲發雜,async/await的寫法更加簡單。使異步代碼看起來更像同步。

數組扁平化

  • 主要思想是循環數組的每一項,把是數組的每一項拆開並放進新數組中。
let ary = [1,2,[3,4,5,[6,7]],8];
let arr = [];
ary.forEach(item=>{
    if(Array.isArray(item)){
        arr = arr.concat(...item)
    }else{
        arr = arr.concat(item)
    }
})
console.log(arr)//[1,2,3,4,5,6,7,8]
複製代碼

null和undefined的區別

  • undefined未被定義的
    • 聲明變量可是未賦值,就等於undefined
    • 調用函數時,應該提供的參數沒有提供,參數就爲undefind
    • 函數沒有返回值的時候,默認返回undefined
  • null還沒有存在的對象
    • 做爲函數的參數,表示函數的參數不是對象
    • 最爲對象原型鏈的終點
  • null == undefined //true
  • null === undefined //fales

理解運算符&&和||和!!

  • && 邏輯與(且);判斷是否爲true,前面是true取後面,前面是false取前面。使用場景以下
    • 在if判斷語句中,充當且的意思,所有都爲true才爲true,其中一個爲flase則爲false。
    • &&後面爲函數的狀況,n>5 && fn();前面爲true則執行fn,前面爲flase則不執行函數。
    • 在取值狀況下,let n = 5 && 3;前面成立取後面,故取n = 3;若前面不成成立取後邊。
  • || 邏輯或(或);判斷是否爲true,前面爲true取前面,前面爲flase取後面;使用場景以下
    • 取值 let n = n || 5;若是n爲true則爲n,若是n爲false則爲5
  • !! 意思是將右側的值強制轉爲boolean類型;例如!!NAN = false;!!5 = true

js中虛值指的是什麼?

  • js中的虛值指的是在轉化爲布爾類型時值爲false的值。例如空字符串""、NAA、0、undefined、false

event.target和event.currentTarget的區別

  • event.target是觸發事件的元素
  • event.currentTarget是觸發事件所綁定的元素

原生頭像上傳和文件上傳

<div class="main">
        <input type="file" onchange="change(event)" onclick="click()" style="display: none;" id="fileEle"
            multiple='multiple'>
        <div class="avatar" style="width: 50px; height: 50px; border-radius: 100%; background: yellow;" onclick="fn()"></div>
        <img src="" id="img" onclick="getImg()" style="width: 50;height: 50px;background: red;">
</div>
<script>
    //multiple="multiple"表示支持選中多個文件
    let fileEle = document.getElementById('fileEle');
    let img = document.getElementById('img');
    function getImg() {
        fileEle.click()
    }
    function change(event) {
        console.log(event.target.files[0])
        let files = fileEle.files[0];  //fileEle.file是一個Filelist對象
        let render = new FileReader();
        render.readAsDataURL(files);
        render.onload = function () {
            img.setAttribute('src', render.result);
        }
    }
    function fn(){
        fileEle.click()
    }
</script>
複製代碼
相關文章
相關標籤/搜索