国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

ES6所改良的javascript“缺陷”問題

2019-11-20 09:10:38
字體:
供稿:網(wǎng)友

塊級作用域

ES5沒有塊級作用域,只有全局作用域和函數(shù)作用域,由于這一點(diǎn),變量的作用域甚廣,所以一進(jìn)入函數(shù)就要馬上將它創(chuàng)建出來。這就造成了所謂的變量提升。

ES5的“變量提升”這一特性往往一不小心就會造成一下錯(cuò)誤:

1.內(nèi)層變量覆蓋外層變量

var tmp = new Date();function f() {console.log(tmp);if (false) { //執(zhí)行則undefinedvar tmp = "hello world";}}

2.變量泄露,成為全局變量

var s = 'hello';for (var i = 0; i < s.length; i++) {console.log(s[i]);}console.log(i); // 5

往常我們往往是使用閉包來解決這一問題的(比如自執(zhí)行函數(shù))。現(xiàn)在,基于這一問題,ES6增加了塊級作用域,所以不再需要自執(zhí)行函數(shù)了。

let 和 const

ES6是是向后兼容的,而保持向后兼容性意味著永不改變JS代碼在Web平臺上的行為,所以var創(chuàng)建的變量其作用域依舊將會是全局作用域和函數(shù)作用域。這樣以來,即使擁有了塊級作用域,也無法解決ES5的“變量提升”問題。所以,這里ES6新增了倆個(gè)新關(guān)鍵詞:let和const。

1.let

“l(fā)et是更完美的var”,它有著更好的作用域規(guī)則。

2.const

const聲明一個(gè)只讀的常量。一旦聲明,常量的值就不能改變,但const聲明的對象可以有屬性變化(對象凍結(jié)Object.freeze)

const a = [];a.push('Hello'); // 可執(zhí)行a = ['Dave']; // 報(bào)錯(cuò)

也可以使用Object.freeze將對象凍結(jié)

const foo = Object.freeze({});// 常規(guī)模式時(shí),下面一行不起作用;// 嚴(yán)格模式時(shí),該行會報(bào)錯(cuò)foo.prop = 123;//

使用let和const:

•變量只在聲明所在的塊級作用域內(nèi)有效

•變量聲明后方可使用(暫時(shí)性死區(qū))

•不能重復(fù)定義變量

•聲明的全局變量,不屬于全局對象的屬性

var a = 1;window.a // 1let b = 1;window.b // undefined

this關(guān)鍵字

我們知道,ES5函數(shù)中的this指向的是運(yùn)行時(shí)所在的作用域。比如

function foo() {setTimeout(function(){console.log('id:', this.id);}, 100);}var id = 21;foo.call({id:42});//id: 21

在這里,我聲明了一個(gè)函數(shù)foo,其內(nèi)部為一個(gè)延遲函數(shù)setTimeout,每隔100ms打印一個(gè)this.id。我們通過foo.call({id:42})來調(diào)用它,并且為這個(gè)函數(shù)設(shè)定作用域。它真正執(zhí)行要等到100毫秒后,由于this指向的是運(yùn)行時(shí)所在的作用域,所以這里的this就指向了全局對象window,而不是函數(shù)foo。這里:

•使用call來改變foo的執(zhí)行上下文,使函數(shù)的執(zhí)行上下文不再是window,從而來辨別setTimeout中的this指向

•setTimeout方法掛在window對象下,所以其this指向執(zhí)行時(shí)所在的作用域――window對象。

超時(shí)調(diào)用的代碼都是在全局作用域中執(zhí)行的,因此函數(shù)中this 的值在非嚴(yán)格模式下指向window 對象,在嚴(yán)格模式下是undefined --《javascript高級程序設(shè)計(jì)》

為了解決這一問題,我們往常的做法往往是將this賦值給其他變量:

function foo() {var that = this;setTimeout(function(){console.log('id:', that.id);}, 100);}var id = 21;foo.call({id:42});//id: 42

而現(xiàn)在ES6推出了箭頭函數(shù)解決了這一問題。

箭頭函數(shù)

標(biāo)識符=> 表達(dá)式

var sum = (num1, num2) => { return num1 + num2; }// 等同于var sum = function(num1, num2) {return num1 + num2;};

•如果函數(shù)只有一個(gè)參數(shù),則可以省略圓括號

•如果函數(shù)只有一條返回語句,則可以省略大括號和return

•如果函數(shù)直接返回一個(gè)對象,必須在對象外面加上括號。(因?yàn)橐粋€(gè)空對象{}和一個(gè)空的塊 {} 看起來完全一樣。所以需要用小括號包裹對象字面量。)

針對this關(guān)鍵字的問題,ES6規(guī)定箭頭函數(shù)中的this綁定定義時(shí)所在的作用域,而不是指向運(yùn)行時(shí)所在的作用域。這一以來,this指向固定化了,從而有利于封裝回調(diào)函數(shù)。

function foo() {var that = this;setTimeout(()=>{console.log('id:', that.id);}, 100);} var id = 21;foo.call({id:42});//id: 42

注意:箭頭函數(shù)this指向的固定化,并不是因?yàn)榧^函數(shù)內(nèi)部有綁定this的機(jī)制,實(shí)際原因是箭頭函數(shù)根本沒有自己的this。而箭頭函數(shù)根本沒有自己的this,其內(nèi)部的this也就是外層代碼塊的this。這就導(dǎo)致了其:

•不能用作構(gòu)造函數(shù)

•不能用call()、apply()、bind()這些方法去改變this的指向

類與繼承

傳統(tǒng)ECMAScript沒類的概念,它描述了原型鏈的概念,并將原型鏈作為實(shí)現(xiàn)繼承的主要方法。其基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。而實(shí)現(xiàn)這一行為的傳統(tǒng)方法便是通過構(gòu)造函數(shù):

function Point(x, y) {this.x = x;this.y = y;}Point.prototype.toString = function () {return '(' + this.x + ', ' + this.y + ')';};var p = new Point(1, 2);

在這里,構(gòu)造函數(shù)Point會有一個(gè)原型對象(prototype),這個(gè)原型對象包含一個(gè)指向Point的指針(constructor),而實(shí)例p包含一個(gè)指向原型對象的內(nèi)部指針(prop)。所以整個(gè)的繼承是通過原型鏈來實(shí)現(xiàn)的。詳情可見我的這篇文章:javascript中的prototype和constructor

class

ES6提供了更接近傳統(tǒng)語言的寫法,引入了Class(類)這個(gè)概念,作為對象的模板。通過class關(guān)鍵字,可以定義類。但是類只是基于原型的面向?qū)ο竽J降恼Z法糖。對于class的引入,褒貶不一,很多人認(rèn)為它反而是一大缺陷,但對我來說,這是一個(gè)好的語法糖,因?yàn)橥5脑玩溊^承的方式往往能把我繞那么一會兒。

//定義類class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return '(' + this.x + ', ' + this.y + ')';}}var p = new Point(1, 2);

•類里面有一個(gè)constructor方法,它是類的默認(rèn)方法,通過new命令生成對象實(shí)例時(shí),自動調(diào)用該方法。一個(gè)類必須有constructor方法,如果沒有顯式定義,一個(gè)空的constructor方法會被默認(rèn)添加。

•constructor方法中的this關(guān)鍵字代表實(shí)例對象,

•定義“類”的方法(如上例的toString)的時(shí)候,前面不需要加上function這個(gè)關(guān)鍵字,直接把函數(shù)定義放進(jìn)去了就可以了。另外,方法之間不需要逗號分隔,加了會報(bào)錯(cuò)。

•使用的時(shí)候,也是直接對類使用new命令,跟構(gòu)造函數(shù)的用法完全一致

•類的所有方法都定義在類的prototype屬性上面

class的繼承――extend

Class之間可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承,這比ES5的通過修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多。

class ColorPoint extends Point {constructor(x, y, color) {super(x, y); // 調(diào)用父類的constructor(x, y)this.color = color;}toString() {return this.color + ' ' + super.toString(); // 調(diào)用父類的toString()}}

•super關(guān)鍵字,作為函數(shù)調(diào)用時(shí)(即super(...args)),它代表父類的構(gòu)造函數(shù);作為對象調(diào)用時(shí)(即super.prop或super.method()),它代表父類。在這里,它表示父類的構(gòu)造函數(shù),用來新建父類的this對象。

•子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會報(bào)錯(cuò)。這是因?yàn)樽宇悰]有自己的this對象,而是繼承父類的this對象,然后對其進(jìn)行加工。如果不調(diào)用super方法,子類就得不到this對象。

模塊化

歷史上,JavaScript一直沒有模塊(module)體系,無法將一個(gè)大程序拆分成互相依賴的小文件,再用簡單的方法拼裝起來,這對開發(fā)大型的、復(fù)雜的項(xiàng)目形成了巨大障礙。為了適應(yīng)大型模塊的開發(fā),社區(qū)制定了一些模塊加載方案,比如CMD和AMD。

ES6的模塊化寫法:

import { stat, exists, readFile } from 'fs';

上面代碼的實(shí)質(zhì)是從fs模塊加載3個(gè)方法,其他方法不加載。這種加載稱為“編譯時(shí)加載”,即ES6可以在編譯時(shí)就完成模塊加載,效率要比CommonJS模塊的加載方式高。當(dāng)然,這也導(dǎo)致了沒法引用ES6模塊本身,因?yàn)樗皇菍ο蟆?br />

模塊功能主要由兩個(gè)命令構(gòu)成:

•export

用于規(guī)定模塊的對外接口,對外的接口,必須與模塊內(nèi)部的變量建立一一對應(yīng)關(guān)系。

// 寫法一export var m = 1;//錯(cuò)誤export 1;// 寫法二var m = 1;export {m};//錯(cuò)誤export m;// 寫法三 重命名var n = 1;export {n as m};

•import

用于輸入其他模塊提供的功能,它接受一個(gè)對象(用大括號表示),里面指定要從其他模塊導(dǎo)入的變量名(也可以使用*號整體加載)

字符串插值

在javascript的開發(fā)中,我們常常需要這樣來輸出模板:

function sayHello(name){return "hello,my name is "+name+" I am "+getAge(18);}function getAge(age){return age;}sayHello("brand") //"hello,my name is brand I am 18"

我們需要使用+來連接字符串和變量(或者表達(dá)式)。例子比較簡單,所以看上去無傷大雅,但是一旦在比較復(fù)雜的情況下,就會顯得相當(dāng)繁瑣不方便,這一用法也讓我們不厭其煩。對此,ES6引入了模板字符串,可以方便優(yōu)雅地將 JS 的值插入到字符串中。

模板字符串

對于模板字符串,它:

•使用反引號``包裹;

•使用${}來輸出值;

•${}里的內(nèi)容可以是任何 JavaScript 表達(dá)式,所以函數(shù)調(diào)用和算數(shù)運(yùn)算等都是合法的;

•如果一個(gè)值不是字符串,它將被轉(zhuǎn)換為字符串;

•保留所有的空格、換行和縮進(jìn),并輸出到結(jié)果字符串中(可以書寫多行字符串)

•內(nèi)部使用反引號和大括號需要轉(zhuǎn)義,轉(zhuǎn)義使用反斜杠/

對于上面的例子,模板字符串的寫法是:

function sayHello(name){return `hello,my name is ${name} I am ${getAge(18)}`;}function getAge(age){return age;}sayHello("brand") //"hello,my name is brandI am 18"

嚴(yán)格模式

嚴(yán)格模式的目標(biāo)之一是允許更快地調(diào)試錯(cuò)誤。幫助開發(fā)者調(diào)試的最佳途徑是當(dāng)確定的問題發(fā)生時(shí)拋出相應(yīng)的錯(cuò)誤(throw errors when certain patterns occur),而不是悄無聲息地失敗或者表現(xiàn)出奇怪的行為(非嚴(yán)格模式下經(jīng)常發(fā)生)。嚴(yán)格模式下的代碼會拋出更多的錯(cuò)誤信息,能幫助開發(fā)者很快注意到一些必須立即解決的問題。在 ES5 中, 嚴(yán)格模式是可選項(xiàng),但是在 ES6 中,許多特性要求必須使用嚴(yán)格模式,這個(gè)習(xí)慣有助于我們書寫更好的 JavaScript。

以上所述是小編給大家介紹的ES6所改良的javascript“缺陷”問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對武林網(wǎng)網(wǎng)站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 剑河县| 疏附县| 徐汇区| 五大连池市| 泰顺县| 含山县| 景德镇市| 宜昌市| 长沙市| 茶陵县| 英吉沙县| 宣恩县| 镶黄旗| 神木县| 休宁县| 朝阳县| 徐闻县| 瓦房店市| 荆州市| 淅川县| 石楼县| 建湖县| 天等县| 石渠县| 凤凰县| 富宁县| 通江县| 赫章县| 清新县| 昆山市| 顺平县| 白朗县| 牙克石市| 临湘市| 龙州县| 荥经县| 增城市| 兰考县| 邯郸市| 包头市| 屯门区|