前端整理——javaScript部分

来源:https://www.cnblogs.com/fangnianqin/archive/2019/01/02/9485847.html
-Advertisement-
Play Games

(1)typeof 和 instanceof 1、typeof 對於基本數據類型(boolean、null、undefined、number、string、symbol)來說,除了 null 都可以顯示正確的類型;對於對象來說,除了函數都會顯示 object。 2、instanceof 是通過原型鏈 ...


(1)typeof 和 instanceof

1、typeof 對於基本數據類型(boolean、null、undefined、number、string、symbol)來說,除了 null 都可以顯示正確的類型;對於對象來說,除了函數都會顯示 object。
2、instanceof 是通過原型鏈來判斷的。可以判斷一個對象的正確類型,但是對於基本數據類型的無法判斷。
3、相關筆試題:
1)JavaScript中如何檢測一個變數是一個String類型?請寫出函數實現。

var str = 'ssssssss';
typeof str === 'string'
str.constructor === String

(2)閉包

1、閉包是指有權訪問另一個函數作用域中的變數的函數。
創建閉包的常見方式,就是在一個函數內部創建另一個函數。

 function a(){
        var num = 100;
        function b(){
            console.log(num);
        }
        return b;
    }
    var c = a();
    c(); //100

如上所示:函數b可以訪問到函數a中的變數,函數b就是閉包。

2、閉包的用途:1)讀取函數內部的變數;2)讓這些變數始終保存在記憶體中
由於閉包會攜帶包含它的函數的作用域,因此會比其他函數占用更多的記憶體。過度使用閉包可能會導致記憶體占用過多,建議只在絕對必要時再考慮使用閉包。

3、相關面試題
1)迴圈中使用閉包解決‘var’定義函數的問題

for(var i = 1; i <= 5; i++){
        setTimeout(function timer(){
            console.log(i);
        },2000)
    }

這裡因為setTimeout是非同步執行,迴圈會先執行完畢,這時i等於6,然後就會輸出5個6。解決方法如下所示:
第一種是使用let

for(let i = 1; i <= 5; i++){
        setTimeout(function timer(){
            console.log(i);
        },2000)
    }

第二種是使用閉包

for(var i = 1; i <= 5; i++){
        (function(j){
            setTimeout(function timer(){
                console.log(j);
            },2000)
        })(i)
    }

這裡首先使用了立即執行函數將i傳入函數內部,這個時候值就被固定在了參數j上面不會改變,當下次執行timer這個閉包的時候,就可以使用外部函數的變數j。

(3)原型和原型鏈

1、我們創建的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象。而這個對象的用途是包含可以由特定類型的所有實例共用的屬性和方法。prototype就是通過調動構造函數而創建的那個對象實例的原型對象。
使用原型對象的好處是可以讓所有對象實例共用它所包含的屬性和方法。
示例:

 function Person(){}
    var p1 = new Person();
    var p2 = new Person();
    Person.prototype.name = 'CoCo';
    console.log(p1.name); //CoCo
    console.log(p2.name); //CoCo

Person構造函數下有一個prototype屬性。Person.prototype就是原型對象,也就是實例p1、p2的原型。

2、在預設情況下,所有原型對象都會自動獲得一個constructor屬性,這個屬性包含一個指向prototype屬性所在函數的指針。

function Person(){}
console.log(Person.prototype.constructor === Person); //true

3、Firefox、Safari和Chrome在每個對象上都支持一個屬性__proto__,這個屬性對腳本是完全不可見的。__proto__用於將實例與構造函數的原型對象相連。
連接實例與構造函數的原型對象之間。

function Person(){}
    var p1 = new Person();
    console.log(p1.__proto__ === Person.prototype); //true
    //isPrototypeOf:檢測一個對象是否是另一個對象的原型。或者說一個對象是否被包含在另一個對象的原型鏈中
    console.log(Person.prototype.isPrototypeOf(p1)); //true
    //getPrototypeOf:返回對象__proto__指向的原型prototype
    console.log(Object.getPrototypeOf(p1) == Person.prototype); //true

(4)call、apply、bind

每個函數都包含兩個非繼承而來的方法: appy()和call()。這兩個方法的用途都是在特定的作用域中調用函數,然後可以設置調用函數的this指向。
1、apply()第一個參數是this所要指向的那個對象,如果設為null或undefined或者this,則等同於指定全局對象。二是參數(可以是數組也可以是arguments對象)。

var a = 1;
    var obj1 = {
        a:2,
        fn:function(){
            console.log(this.a)
        }
    };
   obj1.fn(); //2
   obj1.fn.apply(this); //1

2、call()方法可以傳遞兩個參數。第一個參數是指定函數內部中this的指向(也就是函數執行時所在的作用域),第二個參數是函數調用時需要傳遞的參數。第二個參數必須一個個添加。
3、bind()方法可以傳遞兩個參數。第一個參數是指定函數內部中this的指向,第二個參數是函數調用時需要傳遞的參數。第二個參數必須一個個添加。
4、三者區別:
1)都可以在函數調用時傳遞參數,call、bind方法需要直接傳入,而apply方法可以以數組或者arguments的形式傳入。
2)call、bind方法是在調用之後立即執行函數,而bind方法沒有立即執行,需要將函數再執行一遍。
5、手寫三種函數
1)apply

 Function.prototype.myApply = function(context){
            if(typeof this !== 'function'){
                throw new TypeError('Error');
            }
            context = context || window;
            context.fn = this;
            let result;
            if(arguments[1]){
               result = context.fn(...arguments[1]);
            }else{
                result = context.fn();
            }
            delete context.fn;
            return result;
        };

2)call

 Function.prototype.myCall = function(context){
            if(typeof this !== 'function'){
                throw new TypeError('Error');
            }
            context = context || window;
            context.fn = this;
            const args = [...arguments].slice(1);
            const result = context.fn(...args);
            delete context.fn;
            return result;
        };

3)bind

Function.prototype.myBind = function(context){
            if(typeof this !== 'function'){
                throw new TypeError('Error');
            }
           const _this = this;
            const args = [...arguments].slice(1);
             return function F(){
                 if(this instanceof F){
                     return new _this(...args,...arguments);
                 }
                 return _this.apply(context,args.concat(...arguments));
             }
        };

bind返回了一個函數,對於函數來說有兩種方式調用,一種是直接調用,一種是通過new的方式:
直接調用,這裡選擇了apply的方式實現,因為因為 bind 可以實現類似這樣的代碼 f.bind(obj, 1)(2),所以我們需要將兩邊的參數拼接起來,於是就有了這樣的實現 args.concat(...arguments)。
最後來說通過 new 的方式,對於 new 的情況來說,不會被任何方式改變 this,所以對於這種情況我們需要忽略傳入的 this

(5)深拷貝淺拷貝

1、淺拷貝

let a = {
  age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2

基本數據類型是數據拷貝,會重新開闢一個空間存放拷貝的值。對象類型在賦值的過程中其實是複製了地址,從而會導致改變了一方其他也都被改變的情況。通常在開發中我們不希望出現這樣的問題,我們可以使用淺拷貝來解決這個情況。

1)概念:對於對象類型,淺拷貝就是對對象地址的拷貝,拷貝的結果是兩個對象指向同一個地址,並沒有開闢新的棧,修改其中一個對象的屬性,另一個對象的屬性也會改變。

2)實現:
a、通過Object.assign來實現。Object.assign()方法的第一個參數是目標對象,後面的參數都是源對象。用於對象的合併,將源對象的所有可枚舉屬性複製到目標對象。
Object.assign 只會拷貝所有的屬性值到新的對象中,如果屬性值是對象的話,拷貝的是地址,所以並不是深拷貝。

let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

b、通過展開運算符 ... 來實現淺拷貝

let a = {
  age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1

c、迴圈實現
這裡是淺拷貝,因為對象還是拷貝的地址。

 var a = {
        name:'coco',
        age:33,
        fn:function(){
            console.log("111")
        },
        children:{
            age:66
        }
    };
    var b = {};
    for(var i in a){
        b[i] = a[i];
    }
    b.children.age = 100;
    console.log(a);
    console.log(b);

2、深拷貝

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native

淺拷貝只解決了第一層的問題,如果接下去的值中還有對象的話,那麼就又回到最開始的話題了,兩者享有相同的地址。要解決這個問題,我們就得使用深拷貝了。

1)概念:對於對象類型,深拷貝會開闢新的棧,兩個對象對應兩個不同的地址,修改其中一個對象的屬性,另一個對象的屬性不會改變。
2)原理:深複製--->實現原理,先新建一個空對象,記憶體中新開闢一塊地址,把被覆制對象的所有可枚舉的(註意可枚舉的對象)屬性方法一一複製過來,註意要用遞歸來複制子對象裡面的所有屬性和方法,直到子子.....屬性為基本數據類型。
3)實現:
a、通過 JSON.parse(JSON.stringify(object)) 來解決
缺點:可以滿足基本的深拷貝,但是對於正則表達式、函數類型則無法進行拷貝。它還會拋棄對象的constructor。

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

b、遞歸

var a = {
        name:'kiki',
        age:25,
        children:{
            name:'CoCo',
            age:12
        },
        arr:['111','222'],
        fn:function(){
            console.log(1);
        }
    };

    function copy(obj){
        if(obj instanceof Array){
            var newObj = [];
        }else{
            var newObj = {};
        }
       for(var i in obj){
            if(typeof obj[i] == 'object'){
                newObj[i] = copy(obj[i]);
            }else{
                newObj[i] = obj[i];
            }
       }
       return newObj;
    }
    var b = copy(a);
    console.log(a);
    console.log(b);

c、jQuery.extend()
jQuery.extend([deep],target,object1,object2...),deep位Boolean類型,如果為true則進行深拷貝。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • (註:此文是在看過許多學習資料和視頻之後,加上自身理解拼湊而成,僅作學習之用。若有版權問題,麻煩及時聯繫) 標準頁面結構: Html發展歷史: 註:每一種HTML需要有對應的doctype聲明。 H5 <!doctype html> 無文檔聲明瀏覽器以怪異模式解析html Html標簽: 不使用ht ...
  • (1)盒模型(普通盒模型、怪異盒模型) 1、元素的content(內容)、padding(內邊距)、border(邊框)、margin(外邊距)構成了CSS盒模型 2、IE盒模型和W3C盒模型 1)IE盒模型是怪異模式下的盒模型,W3C盒模型是標準模式下的盒模型; 2)IE盒模型的width/hei ...
  • (1)Vue的生命周期 1)創建vue實例,初始化生命周期鉤子函數 2)數據檢測及方法和計算屬性代理。在數據檢測和初始化數據之前調用beforeCreated(),這時還獲取不到props或者data中的數據;數據、屬性、方法初始化之後,調用created(),可以訪問之前訪問不到的數據,但是組件還 ...
  • function getBrowserInfo() { var ua = navigator.userAgent.toLocaleLowerCase(); var browserType = null; if (ua.match(/msie/) != null || ua.match(/triden... ...
  • 最近項目不太忙,有時間系統學習了一下rxjs的一些知識,將其中個人認為比較常用的一些操作符mark下來,分享學習 ...
  • 瀏覽器中的JavaScript: 1.基於ECMAscript規範,這個規範規定了語法 2.添加了dom:用來處理文檔 document object model 3.添加了BOM:用於操作瀏覽器 window location histrory navigator Node中的JavaScript ...
  • 身為一個前端攻城獅,是不是經常遇到各種各樣的響應式問題?下麵我們來說一下: 1.響應式跟自適應有什麼區別? 有些人可能還不知道響應式跟自適應的區別,甚至認為他們是同一個東西,其實不是的. 自適應是最早出現的,後面才有了響應式。響應式佈局等於流動網格佈局,而自適應佈局等於使用固定分割點來進行佈局。 如 ...
  • 由於升級了 v0.2 版 GearCase 使用打包工具從 parcel 更換成 vue-cli 3.x。因此打包後發佈 NPM 包的方式與之前有很大的差異,這也導致了在發佈完 GearCase v0.2.2 版本之後,我自己在進行 NPM / Yarn 安裝包時。根本無法通過之前文檔的方式,進行引 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...