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