講義內(nèi)容:JS 誕生的背景、基本類型、運算符
以下內(nèi)容只涉及 ES5 標準,ES6 增加的新內(nèi)容可以在網(wǎng)上查找到。
JS 誕生的背景上世紀 90 年代網(wǎng)景公司開發(fā)的瀏覽器獨步天下
一個叫做 Brendan Eich 的工程師受命于開發(fā)一款腳本語言,來增強瀏覽器的功能。
這名工程師花費了 10 天時間設(shè)計出了第一個版本,名叫 LiveScript。
后來因為當時 Java 正紅,公司將其改名為 JavaScript,所以 JS 和 Java 其實沒有什么關(guān)系。
這名工程師在設(shè)計語言之初有幾個目標
簡單易用,不需要專業(yè)的計算機知識就能使用
因為個人的喜愛,所以增加對函數(shù)式編程的支持
因為公司壓力,所以也要支持面向?qū)ο?/p>
后來 JS 因為市場認同,打敗了 VBScript,Java plugin 等一系列增強瀏覽器的方案,成了事實標準。
網(wǎng)景公司倒閉之后,JS 的標準制定由 ECMA(歐洲電腦制造商協(xié)會)制定,所以又叫做 ECMAScript, 新的標準叫做 ES6、ES7、ES2018 … 每年會收集各種語言規(guī)范建議,通過 草案、stage1、stage2 等幾個階段,并在瀏覽器中有實現(xiàn)后會成為正式標準。
所以 JS 具有以下特點:
向下兼容,包括兼容 bug(typeof null,大數(shù))
奇怪、蹩腳的規(guī)范,從技術(shù)上來說缺點很多
運用場景廣泛
迭代速度快,
會在項目里使用還在草案階段的新語法
變種、超集、子集 很多(coffee script, typescript, Action Script, flow, AssembleScript)
基本類型JS 中的基本類型有以下幾種:
undefined
null
Boolean
Number
String
另外有三種引用類型:
Function
Array
Object
和 Java 一樣,所有類型都是基于 Object(除了 undefined ?)
通過 「var」關(guān)鍵字聲明一個變量,方法和大多數(shù)語言一樣。
JS 是動態(tài)語言,變量不用區(qū)分類型,不同類型之間的變量可以相互賦值。
var foo = 1; var bar; var a, b, c; bar = foo = “abcd” undefined 和 null
當一個值沒有初始值的時候,默認值為 undefined。
undefined 在 JS 中是個語言設(shè)計的缺陷例子。
undefined 的行為在大多數(shù)情況下和 null 一樣,都是不可訪問的值,但是在 typeof 的時候結(jié)果不同
var und; var nl = null; typeof und === ’undefined’ typeof nl == ‘object’數(shù)字
Boolean, Number,String 的行為和大多數(shù)語言一樣。
可以直接聲明也可以通過構(gòu)造函數(shù)、工廠模式聲明,三者沒什么區(qū)別。
var a = 123 var a = new Number(123) var a = Number(123)
在 JS 中 數(shù)字的取值范圍是 -253 - 1 到 253 - 1,范圍小于 long 型,并且計算時有精度問題
1.2 / 0.2 // 5.999999999999999
聲明數(shù)字的方式和其它語言類似,科學計數(shù)法、八進制、十六進制
var a = 1e3 // 1000 var a = 0o12 // 10 var a = 0xa // 10
通過 「toString」方法可以轉(zhuǎn)換成字符串,并設(shè)置進制
var a = 1000 a.toString(10) // “1000” a.toString(8) // “1750” a.toString(16) // “3e8”
在 JS 中,有兩個特殊的數(shù)字,NaN 和 Infinity。
當字符串或者其他類型轉(zhuǎn)換成數(shù)字失敗的時候,就會返回 NaN,但是 NaN 的類型依然是 number。
NaN 和任何數(shù)字計算后,結(jié)果都是 NaN。
當數(shù)字除以 0 的時候,就會返回 Infinity。
Number(undefined) // NaN Number(null) // 我也很費解,為什么 null 轉(zhuǎn)換成數(shù)字就是 0 // 0 Number("asdf") // NaN 10 / 0 //Infinity字符串
在 JS 中字符串是可變長,而且可以通過 「+」 操作符做拼接。
字符串在內(nèi)容中應(yīng)該是雙字節(jié)儲存,可以通過索引訪問每個字符,而不是每個 byte。
在瀏覽器中編碼格式根據(jù)網(wǎng)頁的編碼格式而設(shè)置(在 node 中默認是 UTF8?)
在 JS 中,聲明一個字符串通過單引號或者雙引號都可以,二者沒有區(qū)別。通常習慣是通過單引號訪問,因為可以少按一個 shift。
var a = ‘123’ var b = “123” a == b a[0] // 通過索引訪問的結(jié)果仍然是個字符串 // “1”函數(shù)
函數(shù)在 JS 中是一等公民,可以賦值給變量,有兩種聲明方式
function plus(a, b) { return a + b} var plus = function(a, b) { return a + b }
第二種方法其實是將一個「匿名函數(shù)」復制給了變量 plus。
這兩種方式在使用上沒太大區(qū)別,除了在「聲明前置」的場景下會有點區(qū)別
匿名函數(shù)還有一種方法叫做「立即執(zhí)行函數(shù)」。
(function(a, b){ return a + b })(10, 20) // 30
函數(shù)只會將 return 聲明的表達式的值返回出去,在函數(shù)沒有聲明 return 的時候,默認返回 undefined
function plus (a, b) { a + b } plus(1, 2) // undefined
函數(shù)和作用域
函數(shù)和變量一樣,可以在任何地方聲明、使用,
每個函數(shù)獨立出了一個作用域,作用域可以互相嵌套。
函數(shù)作為一個變量,本身也在父作用域下
function foo(b) { var a = 10 // 這里屬于 foo 的作用域,內(nèi)部有 bar, b, a 三個變量 function bar() { var c = 20; return a + b + c // 這里屬于 bar 的作用域,因為在 foo 之內(nèi),所以可以訪問 a 和 b } // 這里不能訪問 c return bar(); }
由于 JS 在設(shè)計的時候,怕用戶不理解變量需要先聲明再使用,所以對變量會有「聲明前置」,幫助大家提前聲明所需要的變量。
下面我們用立即執(zhí)行函數(shù)創(chuàng)建一個閉包來解釋什么叫「聲明前置」
(function() { console.log(fn, foo); function fn(a, b){ return a + b }; var foo = 1234; console.log(fn, foo); })() // function (a, b){ return a + b } undefined // function (a, b){ return a + b } 1234
上面的代碼相當于:
(function() { function fn(a, b){ return a + b }; var foo; console.log(fn, foo);? foo = 1234; console.log(fn, foo); })()
如果我們用匿名函數(shù)賦值給一個變量,那么會有下面效果:
(function() { console.log(fn, foo); var fn = function(a, b){ return a + b }; var foo = 1234; console.log(fn, foo); })() // undefined undefined // function (a, b){ return a + b } 1234
上面的代碼相當于:
(function() { var fn, foo; console.log(fn, foo); fn = function(a, b) { return a + b}; foo = 1234; console.log(fn, foo); })()數(shù)組
在 JS 中數(shù)組是可變的,而且數(shù)組內(nèi)可以放任何值。
數(shù)組的長度是最后一個元素的索引加一。
如果訪問沒有設(shè)置的元素,將會返回 unfined
var array = []; array[0] = 1; array[2] = “1234”; array[4] = function(){}; // [1, undefined, “1234”, function(){}] array[1] // undefined
js 數(shù)組中自帶了很多方法,方便我們對數(shù)組做操作,比如說 map, reduce 等等
[1, 2, 3].map(function(d) { return d + 1 }) // [2, 3, 4] [1, 2, 3].reduce(function(r, d) { return r + d }, 0) // 6
如果想要刪除數(shù)組中的某個元素的話,我們可以用 delete 關(guān)鍵詞,或者直接將索引的位置設(shè)置成 undefined
var array = [1, 2, 3] delete array[1] // [1, undefined, 3]
如果我們需要刪除數(shù)組中某個元素,并且縮短數(shù)組長度的話,就需要用到 splice。
var array = [1, 2, 3] array.splice(1, 1) console.log(array) // [1, 3]
一些常用的數(shù)組方法還有 slice, forEach, find, every, includes 等等
對象和 java 一樣,對象(Object) 是所有類型的基類。它類似 JSON 里的鍵值對結(jié)構(gòu)體,可以動態(tài)的掛載任何屬性。
聲明的方法有兩種,{} 和 new
var a = {} var b = new Object() a.num = 1 a.str = "1234" console.log(a) // { num: 1, str: "1234"}
對象(Object)有點類似 Java 里的 HashMap,但 Key 只能是字符串。可以通過類似數(shù)組索引的方式來訪問對象上的鍵。
這種方法和點操作符是一樣的效果,當鍵名由一些特殊的字符組成的時候,我們可以通過索引方式訪問。
var obj = {value: 1234} console.log(obj["value"]) // 1234
這樣聲明或者訪問會報錯:
var obj = { some-value: 1234 } obj.some-value
我們需要讓編譯器知道 some-value 是一個鍵名,所以需要將它們用引號括起來
var obj = { "some-value": 1234 } obj["some-value"]
當一個對象中掛載了一個函數(shù),在函數(shù)中可以通過 this 來訪問對象內(nèi)的其他屬性,this 也可以理解為「執(zhí)行上下文」
function fn () { console.log(this.value) } var obj = { fn: fn, value: 1234 } obj.fn() // 此時 fn 的執(zhí)行上下文就是 obj // 1234 var otherObj = { fn: fn, value: "abcd"} otherObj.fn() // 此時 fn 的執(zhí)行上下文就是 otherObj // "abcd"
由于函數(shù)和數(shù)組是所有類型的基類,所以可以像對象一樣隨意的擴展屬性。
但是字面量(如數(shù)字、布爾值、字符串、null、undefined) 是不能隨意擴展的。
function plus(a, b) { return a + b} plus.value = 1234 plus(12, plus.value) // 1246 var array = [] array.value = 1234 console.log(array.value) // 1234 var a = true; a.value = 1234 console.log(a.value) // undefined運算符
JS 的運算符和其他語言基本類似,就+-*%/這些,外加一些二進制操作符。
但因為 JS 弱類型的特性,有些場景是其他語言沒有的,比如一個數(shù)字加一個字符串,結(jié)果是什么?
1+"2" // "12"
這種場景還可以理解,數(shù)字和字符串相加的時候,數(shù)字通過調(diào)用 toString 被轉(zhuǎn)換成了字符串。
1 + {} // "1[object Object]"
數(shù)字和對象相加的時候,對象和數(shù)字都調(diào)用了 toString,被轉(zhuǎn)換成了字符串
{} + [] // 0
但是空對象和空數(shù)組相加結(jié)果卻是 0,我也不知道為什么
var obj = {} if (obj) console.log("obj is true") // "obj is true" obj == true // false
上面這個例子中,obj 是個空對象,在 if 條件判斷中被當作真值,但是和 true 對比的時候卻返回 false。
JS 的隱式轉(zhuǎn)換規(guī)則很詭異,很多都是為了兼容早期版本中錯誤的實現(xiàn),這里沒必要細究轉(zhuǎn)換規(guī)則是什么。
我們只需要記住以后用嚴格相等符(===)作對比,避免不同類型的變量相互運算。
"1" == 1 // true "1" === 1 // false循環(huán)
JS 的循環(huán)和其它類似,也都是 for, do..while 這種寫法。
但是,我們一般不用 for 作循環(huán),而是用數(shù)組方法 forEach,map(因為 for 寫起來很麻煩,而且還需要多帶帶聲明一個變量)
[1, 2, 3].forEach(function(value) { return value + 1; }) // [2, 3, 4]
另外還可以通過 for...in 來遍歷一個對象
var obj = {a:1, b:2, c: 3} for (var key in obj) { console.log(key) } // "a" // "b" // "c"
但我們一般也不這么用,而是用 Object.keys 取得包含對象所有鍵的數(shù)組
var obj = {a:1, b:2, c: 3} Object.keys(obj) // ["a", "b", "c"] Object.keys(obj).forEach(console.log) // "a" // "b" // "c"課后習題
第一題:JS 的運用領(lǐng)域都有哪些,作為弱類型的語言執(zhí)行效率如何,為什么?
第二題:typeof 關(guān)鍵字的返回值有幾種結(jié)果?
第三題:下面兩種寫法有什么區(qū)別
{ 0: "a", 1: "b", 2: "c" } ["a","b","c"]
第四題:下面代碼的運行時會不會報錯,this 指向哪里?
function fn () { console.log(this.value) } fn()
第五題:聲明的變量是如何被回收的
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96083.html
摘要:上一章前端教學講義基礎(chǔ)閉包高階函數(shù)閉包是一種打通兩個作用域的能力,在和中都有類似的功能,中的閉包和他們沒有太大的差別。在中任何函數(shù)都可以當作構(gòu)造函數(shù)并搭配關(guān)鍵詞使用。再將作為運行構(gòu)造函數(shù)。 上一章:前端教學講義:JS基礎(chǔ) 閉包、高階函數(shù) 閉包是一種打通兩個作用域的能力,在 Java 和 OC 中都有類似的功能,JS 中的閉包和他們沒有太大的差別。 不過因為 JS 的函數(shù)是一等公民,所以...
摘要:另一個賦值語句將名稱關(guān)聯(lián)到出現(xiàn)在莎士比亞劇本中的所有去重詞匯的集合,總計個。表達式是一個復合表達式,計算出正序或倒序出現(xiàn)的莎士比亞詞匯集合。在意圖上并沒有按照莎士比亞或者回文來設(shè)計,但是它極大的靈活性讓我們用極少的代碼處理大量文本。 1.1 引言 來源:1.1 Introduction 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 計算機科學是一個極其寬泛的學科。全球的分布...
摘要:請回復這個帖子并注明組織個人信息來申請加入。權(quán)限分配靈活,能者居之。數(shù)量超過個,在所有組織中排名前。網(wǎng)站日超過,排名的峰值為。導航歸檔社區(qū)自媒體平臺微博知乎專欄公眾號博客園簡書合作侵權(quán),請聯(lián)系請抄送一份到贊助我們 Special Sponsors showImg(https://segmentfault.com/img/remote/1460000018907426?w=1760&h=...
閱讀 2024·2021-11-15 11:38
閱讀 2058·2019-08-30 15:55
閱讀 2192·2019-08-30 15:52
閱讀 3175·2019-08-30 14:01
閱讀 2693·2019-08-30 12:47
閱讀 1158·2019-08-29 13:17
閱讀 1072·2019-08-26 13:55
閱讀 2640·2019-08-26 13:46