国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

javascript中為什么我們不能直接使用export?

URLOS / 2162人閱讀

摘要:我們可以認為,宏任務中還有微任務這里不再多做解釋可能會執行的代碼包括腳本模塊和函數體。聲明聲明永遠作用于腳本模塊和函數體這個級別,在預處理階段,不關心賦值的部分,只管在當前作用域聲明這個變量。

相信很多人最開始時都有過這樣的疑問
假如我的項目目錄下有一個 index.html, index.js 于是我像這樣寫

在瀏覽器之間打開index.html,發現

這到底是為什么?為什么連chrome瀏覽器竟然還不完全支持es6的語法?
其實,ES6之前已經出現了js模塊加載的方案,最主要的是CommonJS和AMD規范。commonjs主要應用于服務器,實現同步加載,如nodejs。AMD規范應用于瀏覽器,如requirejs,為異步加載。同時還有CMD規范,為同步加載方案如seaJS。
ES6在語言規格的層面上,實現了模塊功能,而且實現得相當簡單,完全可以取代現有的CommonJS和AMD規范,成為瀏覽器和服務器通用的模塊解決方案。話有回到我們剛才的問題 "為什么chrome瀏覽器竟然還不完全支持es6的語法"

首先,JavaScript有兩種源文件,一種叫做腳本,一種叫做模塊。這個區分是在ES6引入了模塊機制開始的,在ES5和之前的版本中,就只有一種源文件類型(就只有腳本)。

腳本是可以由瀏覽器或者node環境引入執行的,而模塊只能由JavaScript代碼用import引入執行。

從概念上,我們可以認為腳本具有主動性的JavaScript代碼段,是控制宿主完成一定任務的代碼;而模塊是被動性的JavaScript代碼段,是等待被調用的庫。

我們對標準中的語法產生式做一些對比,不難發現,實際上模塊和腳本之間的區別僅僅在于是否包含import 和 export。

腳本是一種兼容之前的版本的定義,在這個模式下,沒有import就不需要處理加載“.js”文件問題。

現代瀏覽器可以支持用script標簽引入模塊或者腳本,如果要引入模塊,必須給script標簽添加type=“module”。如果引入腳本,則不需要type。

這樣,就回答了我們標題中的問題,script標簽如果不加type=“module”,默認認為我們加載的文件是腳本而非模塊,如果我們在腳本中寫了export,當然會拋錯。

其中腳本中可以包含語句。模塊中可以包含三種內容:import聲明,export聲明和語句。先來講講import聲明和export聲明。

import聲明
我們首先來介紹一下import聲明,import聲明有兩種用法,一個是直接import一個模塊,另一個是帶from的import,它能引入模塊里的一些信息。

import "mod"; //引入一個模塊
import v from "mod"; //把模塊默認的導出值放入變量v
直接import一個模塊,只是保證了這個模塊代碼被執行,引用它的模塊是無法獲得它的任何信息的。

帶from的import意思是引入模塊中的一部分信息,可以把它們變成本地的變量。

帶from的import細分又有三種用法,我們可以分別看下例子:

import x from "./a.js" 引入模塊中導出的默認值。
import {a as x, modify} from "./a.js"; 引入模塊中的變量。
import * as x from "./a.js" 把模塊中所有的變量以類似對象屬性的方式引入。

第一種方式還可以跟后兩種組合使用。

import d, {a as x, modify} from "./a.js"
import d, * as x from "./a.js"

語法要求不帶as的默認值永遠在最前。注意,這里的變量實際上仍然可以受到原來模塊的控制。
我們看一個例子,假設有兩個模塊a和b。我們在模塊a中聲明了變量和一個修改變量的函數,并且把它們導出。我們用b模塊導入了變量和修改變量的函數。

模塊a:

export var a = 1;
export function modify(){
    a = 2;
}

模塊b:

import {a, modify} from "./a.js";
console.log(a);
modify(); 
console.log(a);

當我們調用修改變量的函數后,b模塊變量也跟著發生了改變。這說明導入與一般的賦值不同,導入后的變量只是改變了名字,它仍然與原來的變量是同一個。

export聲明
我們再來說說export聲明。與import相對,export聲明承擔的是導出的任務。

模塊中導出變量的方式有兩種,一種是獨立使用export聲明,另一種是直接在聲明型語句前添加export關鍵字。

獨立使用export聲明就是一個export關鍵字加上變量名列表,例如:

export {a, b, c};
我們也可以直接在聲明型語句前添加export關鍵字,這里的export可以加在任何聲明性質的語句之前,整理如下:

--var
--function (含async和generator)
--class
--let
--const

export還有一種特殊的用法,就是跟default聯合使用。export default 表示導出一個默認變量值,它可以用于function和class。這里導出的變量是沒有名稱的,可以使用import x from "./a.js"這樣的語法,在模塊中引入。

export default 還支持一種語法,后面跟一個表達式,例如:

var a = {};
export default a;

但是,這里的行為跟導出變量是不一致的,這里導出的是值,導出的就是普通變量a的值,以后a的變化與導出的值就無關了,修改變量a,不會使得其他模塊中引入的default值發生改變。

說到這里,就來大致說說export和export default的區別

1.export與export default均可用于導出常量、函數、文件、模塊等
2.在一個文件或模塊中,export、import可以有多個,export default僅有一個
3.通過export方式導出,在導入時要加{ },export default則不需要

或者我們可以這樣理解,export default的本質其實就是講后面的值付給default變量,然后你可以為它取你想要的變量

所以
export default 1   // 執行
export 1 // 報錯    

第二行報錯正式是因為沒有指定對外的接口,而第一句指定為default

在import語句前無法加入export,但是我們可以直接使用export from語法。

export a from "a.js"

JavaScript引擎除了執行腳本和模塊之外,還可以執行函數。而函數體跟腳本和模塊有一定的相似之處

再來談一下函數體

執行函數的行為通常是在JavaScript代碼執行時,注冊宿主環境的某些事件觸發的,而執行的過程,就是執行函數體(函數的花括號中間的部分)。

先看一個例子,感性地理解一下:

setTimeout(function(){
    console.log("go go go");
}, 10000)

這段代碼通過setTimeout函數注冊了一個函數給宿主,當一定時間之后,宿主就會執行這個函數。

我們可以認為,宏任務中(還有微任務,這里不再多做解釋)可能會執行的代碼包括“腳本(script)”“模塊(module)”和“函數體(function body)”。正因為這樣的相似性。

函數體其實也是一個語句的列表。跟腳本和模塊比起來,函數體中的語句列表中多了return語句可以用。

函數體實際上有四種,下面,分別介紹一下。

普通函數體,例如:
function foo(){
    //
}
異步函數體,例如:
async function foo(){
    //
}
生成器函數體,例如:
function *foo(){
    //
}
異步生成器函數體,例如:
async function *foo(){
    //
}

上面四種函數體的區別在于:能否使用await或者yield語句。

說完了三種語法結構,再來介紹下JavaScript語法的全局機制(非嚴格模式):預處理。
這對于我們解釋一些JavaScript的語法現象非常重要。不理解預處理機制我們就無法理解var等聲明類語句的行為。
var聲明
var聲明永遠作用于腳本、模塊和函數體這個級別,在預處理階段,不關心賦值的部分,只管在當前作用域聲明這個變量。

還是先舉個例子。

var a = 1;
function foo() {
    console.log(a);
    var a = 2;
}
foo();

這段代碼聲明了一個腳本級別的a,又聲明了foo函數體級別的a,我們注意到,函數體級的var出現在console.log語句之后。

但是預處理過程在執行之前,所以有函數體級的變量a,就不會去訪問外層作用域中的變量a了,而函數體級的變量a此時還沒有賦值,所以是undefined。再看一個情況:

var a = 1;
function foo() {
    console.log(a);
    if(false) {
        var a = 2;
    }
}
foo();

這段代碼比上一段代碼在var a = 2之外多了一段if,我們知道if(false)中的代碼永遠不會被執行,但是預處理階段并不管這個,var的作用能夠穿透一切語句結構,它只認腳本、模塊和函數體三種語法結構。所以這里結果跟前一段代碼完全一樣,我們會得到undefined。

看下一個例子。

var a = 1;
function foo() {
    var o= {a:3}
    with(o) {
        var a = 2;
    }
    console.log(o.a);
    console.log(a);
}
foo();

在這個例子中,引入了with語句,用with(o)創建了一個作用域,并把o對象加入詞法環境,在其中使用了var a = 2;語句。
在預處理階段,只認var中聲明的變量,所以同樣為foo的作用域創建了a這個變量,但是沒有賦值。
在執行階段,當執行到var a = 2時,作用域變成了with語句內,這時候的a被認為訪問到了對象o的屬性a,所以最終執行的結果,我們得到了2和undefined。
這個行為是JavaScript公認的設計失誤之一(類似的還有雙等 ==),一個語句中的a在預處理階段和執行階段被當做兩個不同的變量,嚴重違背了直覺,但是今天,在JavaScript設計原則“don’t break the web”之下,已經無法修正了,所以這里需要特別的注意。
因為早年JavaScript沒有let和const,只能用var,又因為var除了腳本和函數體都會穿透,人民群眾發明了“立即執行的函數表達式(IIFE)”這一用法,用來產生作用域,例如:

for(var i = 0; i < 20; i ++) {
    void function(i){
        var div = document.createElement("div");
        div.innerHTML = i;
        div.onclick = function(){
            console.log(i);
        }
        document.body.appendChild(div);
    }(i);
}

這段代碼很經典,常常在實際開發中見到,也經常被用作面試題,為文檔添加了20個div元素,并且綁定了點擊事件,打印它們的序號。
我們通過IIFE在循環內構造了作用域,每次循環都產生一個新的環境記錄,這樣,每個div都能訪問到環境中的i。
如果我們不用IIFE:

for(var i = 0; i < 20; i ++) {
    var div = document.createElement("div");
    div.innerHTML = i;
    div.onclick = function(){
        console.log(i);
    }
    document.body.appendChild(div);
}

這段代碼的結果將會是點每個div都打印20,因為全局只有一個i,執行完循環后,i變成了20。

function聲明

function聲明的行為原本跟var非常相似,但是在最新的JavaScript標準中,對它進行了一定的修改,這讓情況變得更加復雜了。
在全局(腳本、模塊和函數體),function聲明表現跟var相似,不同之處在于,function聲明不但在作用域中加入變量,還會給它賦值。
我們看一下function聲明的例子

console.log(foo);
function foo(){

}

這里聲明了函數foo,在聲明之前,我們用console.log打印函數foo,我們可以發現,已經是函數foo的值了。
function聲明出現在if等語句中的情況有點復雜,它仍然作用于腳本、模塊和函數體級別,在預處理階段,仍然會產生變量,它不再被提前賦值:

console.log(foo);
if(true) {
    function foo(){

    }
}

這段代碼得到undefined。如果沒有函數聲明,則會拋出錯誤。
這說明function在預處理階段仍然發生了作用,在作用域中產生了變量,沒有產生賦值,賦值行為發生在了執行階段。
出現在if等語句中的function,在if創建的作用域中仍然會被提前,產生賦值效果。

class聲明

class聲明在全局的行為跟function和var都不一樣。
在class聲明之前使用class名,會拋錯:

console.log(c);
class c{

}

這段代碼我們試圖在class前打印變量c,我們得到了個錯誤,這個行為很像是class沒有預處理,但是實際上并非如此。

我們看個復雜一點的例子:

var c = 1;
function foo(){
    console.log(c);
    class c {}
}
foo();

這個例子中,我們把class放進了一個函數體中,在外層作用域中有變量c。然后試圖在class之前打印c。

執行后,我們看到,仍然拋出了錯誤,如果去掉class聲明,則會正常打印出1,也就是說,出現在后面的class聲明影響了前面語句的結果。

這說明,class聲明也是會被預處理的,它會在作用域中創建變量,并且要求訪問它時拋出錯誤。

class的聲明作用不會穿透if等語句結構,所以只有寫在全局環境才會有聲明作用。

這樣的class設計比function和var更符合直覺,而且在遇到一些比較奇怪的用法時,傾向于拋出錯誤。

按照現代語言設計的評價標準,及早拋錯是好事,它能夠幫助我們盡量在開發階段就發現代碼的可能問題。

針對以上問題以及一些不嚴謹的問題和一些引擎難以優化的錯誤,出現了嚴格模式

設立"嚴格模式"的目的,主要有以下幾個:

  - 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;

  - 消除代碼運行的一些不安全之處,保證代碼運行的安全;

  - 提高編譯器效率,增加運行速度;

  - 為未來新版本的Javascript做好鋪墊。

其中 ES6 的模塊自動采用嚴格模式,不管你有沒有在模塊頭部加上"use strict";

至于平常開發時我們到底要不要使用嚴格模式以及包括要不要使用typescript?每個人都有每個人的觀點!那么,在開發中你是否推薦用嚴格模式來"約束"你的代碼及風格呢?

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109992.html

相關文章

  • 很全很全的JavaScript的模塊講解

    摘要:該模塊實現方案主要包含與這兩個關鍵字,其允許某個模塊對外暴露部分接口并且由其他模塊導入使用。由于在服務端的流行,的模塊形式被不正確地稱為。以上所描述的模塊載入機制均定義在中。 最近一直在搞基礎的東西,弄了一個持續更新的github筆記,可以去看看,誠意之作(本來就是寫給自己看的……)鏈接地址:Front-End-Basics 此篇文章的地址:JavaScript的模塊 基礎筆記...

    lufficc 評論0 收藏0
  • Nodejs模塊加載與ES6模塊加載實現

    摘要:以后需要引用模塊的變量函數類就在這個模塊對象的取出,即使再次進來模塊也不會重新執行,只會從緩存獲取。所以對相同模塊的再次加載都是優先緩存方式,核心模塊的緩存檢查依然優先于文件模塊。內建模塊導出啟動會生成全局變量,提供方法協助加載內建模塊。 原始時代 作為一門語言的引入代碼方式,相較于其他如PHP的include和require,Ruby的require,Python的import機制,...

    陳江龍 評論0 收藏0
  • JavaScriptAMD和ES6模塊的導入導出對比

    摘要:每個模塊內部,變量代表當前模塊。這個變量是一個對象,它的屬性即是對外的接口。加載某個模塊,其實是加載該模塊的屬性。為了方便,為每個模塊提供一個變量,指向。這等同在每個模塊頭部,有一行這樣的命令。 我們前端在開發過程中經常會遇到導入導出功能,在導入時,有時候是require,有時候是import在導出時,有時候是exports,module.exports,有時候是export,expo...

    劉明 評論0 收藏0
  • underscore 系列之如何寫自己的 underscore

    摘要:因為在微信小程序中,和都是,加上又強制使用嚴格模式,為,掛載就會發生錯誤,所以就有人又發了一個,代碼變成了這就是現在的樣子。 前言 在 《JavaScript 專題系列》 中,我們寫了很多的功能函數,比如防抖、節流、去重、類型判斷、扁平數組、深淺拷貝、查找數組元素、通用遍歷、柯里化、函數組合、函數記憶、亂序等,可以我們該如何組織這些函數,形成自己的一個工具函數庫呢?這個時候,我們就要借...

    Invoker 評論0 收藏0
  • 再談JavaScript模塊化

    摘要:應用日益復雜,模塊化已經成為一個迫切需求。異步模塊加載機制。引用的資源列表太長,懶得回調函數中寫一一對應的相關參數假定這里引用的資源有數十個,回調函數的參數必定非常多這就是傳說中的 簡述 緣起 模塊通常是指編程語言所提供的代碼組織機制,利用此機制可將程序拆解為獨立且通用的代碼單元。 模塊化主要是解決代碼分割、作用域隔離、模塊之間的依賴管理以及發布到生產環境時的自動化打包與處理等多個方面...

    MorePainMoreGain 評論0 收藏0

發表評論

0條評論

URLOS

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<