摘要:對象是一個值超出有效范圍時發(fā)生的錯誤。包括返回原數(shù)組包括數(shù)組對象函數(shù)可以用來判斷變量是否為對象數(shù)組對象函數(shù)構(gòu)造函數(shù)與直接賦值是等價的。只適用于,數(shù)組不適用通過可以看出一個值到底是什么類型,其中返回值的第二個值表示該值的構(gòu)造函數(shù)。
這是ES5的入門篇教程的筆記,網(wǎng)址:JavaScript教程,以下內(nèi)容中黑體表示大標(biāo)題,還有一些重點;斜體表示對于自身,還需要下功夫?qū)W習(xí)的內(nèi)容。這里面有一些自己的見解,所以若是發(fā)現(xiàn)問題,歡迎指出~
數(shù)據(jù)類型
只有var存在變量提升,let不存在變量提升。
js內(nèi)部都是以64位浮點數(shù)的形式存儲(64位表示精度),整數(shù)也如此,所以1.0和1是相同的一個數(shù),1.0===1.
JavaScript 語言的底層根本沒有整數(shù)。由于浮點數(shù)不是精確的值,所以涉及小數(shù)的比較和運(yùn)算都不是很準(zhǔn)確。
NaN === NaN 用于判斷是否是NaN。
關(guān)于函數(shù)
函數(shù)執(zhí)行時所在的作用域,是定義時的作用域,而不是調(diào)用時所在的作用域。
函數(shù)參數(shù)不是必須的,JavaScript允許省略參數(shù)(與其他語言不同?。。。?,函數(shù)的length屬性與實際傳入的參數(shù)個數(shù)無關(guān),只反映函數(shù)預(yù)期傳入的參數(shù)個數(shù),如下:
function f(a, b) { return a; } f(1, 2, 3) // 1 f(1) // 1 f() // undefined f(, 1) // SyntaxError: Unexpected token ,... f(undefined, 1) // undefined 省略考前的參數(shù),只有顯式傳入undefined f.length // 2
函數(shù)參數(shù)如果是原始類型的值(數(shù)值、字符串、布爾值),傳遞方式是傳值傳遞,也就是說,在函數(shù)體內(nèi)修改參數(shù)值,不會影響到函數(shù)外部;但是,如果是復(fù)合類型(數(shù)組、對象、其他函數(shù)),傳遞方式是傳址傳遞,將會影響到原始值(如果函數(shù)內(nèi)部修改的內(nèi)容,不是參數(shù)對象的某個屬性,而是替換掉整個參數(shù),這是不會影響到原始值)。
var p = 2; function f(p) { p = 3; // 這只是一個拷貝 } f(p); p // 2 var obj = { p: 1 }; function f(o) { o.p = 2; } f(obj); obj.p // 2 var obj = [1, 2, 3]; function f(o) { o = [2, 3, 4]; // 形參o的值指向的是實參obj的地址,重新對o賦值后,o會指向另一個地址,而obj指向的原地址比那個沒有發(fā)生改變,所以obj不會變化。 } f(obj); obj // [1, 2, 3]
由于JavaScript允許函數(shù)有不定數(shù)目的參數(shù),可以通過arguments對象讀取所有參數(shù),在嚴(yán)格模式下,arguments很多方法都是受到限制的;arguments很像數(shù)組,但它是一個對象(arguments是偽數(shù)組)。
什么是閉包?就是在函數(shù)的內(nèi)部,再定義一個函數(shù),用來得到函數(shù)內(nèi)部的局部變量。閉包兩個最大用處有兩個,一個是可以讀取函數(shù)內(nèi)部的變量,另一個是讓這些變量始終保持在內(nèi)存中,也就是閉包可以使得它的誕生環(huán)境一直存在(這個作用有點不理解,需要去理解系統(tǒng)垃圾回收機(jī)制)。閉包還可以封裝對象的私有屬性和私有方法,如下(跟Java類似):
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = Person("張三"); p1.setAge(25); p1.getAge() // 25
注: 外層函數(shù)每次運(yùn)行,都會生成一個新的閉包,而這個閉包又會保留外層函數(shù)的內(nèi)部變量,所以內(nèi)存消耗很大。因此不能濫用閉包,否則會造成網(wǎng)頁的性能問題。
在JavaScript中,圓括號()是一種運(yùn)算符(以前知道圓括號是執(zhí)行函數(shù)的意思,但它算運(yùn)算符還真的不知道,所以人丑還是要多讀書),跟在函數(shù)名之后,表示調(diào)用該函數(shù),比如,print()就是表示調(diào)用print函數(shù)。不能再函數(shù)的定義之后加上圓括號,會產(chǎn)生語法錯誤,因為JavaScript規(guī)定function關(guān)鍵字出現(xiàn)在行首,一律解釋成語句,而不是表達(dá)式,如下:
function(){ /* code */ }(); // SyntaxError: Unexpected token ... // 以下兩種方法都可以馬上執(zhí)行,這叫做“立即調(diào)用的函數(shù)表達(dá)式”,簡稱IIFE (function(){ /* code */ }()); // 或者 (function(){ /* code */ })();
關(guān)于數(shù)組
JavaScript語言規(guī)定,對象的鍵名一律為字符串,所以數(shù)組的鍵名其實也是字符串,之所以可以用數(shù)值讀取,是因為非字符串的鍵名會被轉(zhuǎn)為字符串(這個以前還真不知道)。
對象中有兩種去讀取成員的方法:點結(jié)構(gòu)(object.key)和方括號結(jié)構(gòu)(object[key])。但是,對于數(shù)值的鍵名,不能使用點結(jié)構(gòu)。因為arr.0的寫法不合法,多帶帶的數(shù)值不能作為標(biāo)識符,所以數(shù)組成員只能用方括號arr[0]表示(方括號是運(yùn)算符,可以接受數(shù)值)。
清空/刪除數(shù)組,可以用length屬性試試哦;當(dāng)然如果設(shè)置length大于數(shù)組個數(shù)時,讀取新增的位置都會返回undefined。
for..in 用于對象,不推薦用于數(shù)組(因為數(shù)組也是對象,可以用非數(shù)字鍵加鍵名,for...in會遍歷所有數(shù)字鍵和非數(shù)字鍵,數(shù)組遍歷肯定遍歷的是數(shù)字鍵);for()循環(huán)、while循環(huán)用于數(shù)組。(en,這個我知道)
數(shù)組的空位和undifined不一樣,但是讀取到的卻是undefined,length屬性不過濾空位,但數(shù)組的forEach方法、for...in結(jié)構(gòu)、以及Object.keys方法進(jìn)行遍歷,空位都會被跳過。空位表示數(shù)組沒有這個元素,所以不會被遍歷;undefined表示數(shù)組有這個元素,但值為undefined,所以遍歷不會跳過。
var a = [, , ,]; a[1] // undefined
這里說的“類似數(shù)組的對象”,在其他地方看到過其他資料,叫做“偽數(shù)組”。
根本特征:具有l(wèi)ength屬性,但是length屬性不是動態(tài)值,不會隨著成員的變化而變化。(其他地方也提到過,arguments也是偽數(shù)組。)
變?yōu)檎嬲臄?shù)組,一是用slice,二時用call()。這兩個內(nèi)容看不懂,還需要努力!
運(yùn)算符
“重載”?。。∥抑辉贘ava里面聽到過函數(shù)重載,js里面運(yùn)算符竟然也有這種叫法,長知識了!什么叫“重載”呢?加法運(yùn)算符在運(yùn)行時決定,是執(zhí)行相加,還是執(zhí)行連接,也就是說,運(yùn)算子的不同,導(dǎo)致了不同的語法行為,這種行為成為“重載”。(只有加法運(yùn)算符才有這種操作,減法、除法和乘法都不會發(fā)生重載,因為其他的算術(shù)運(yùn)算符,有一個規(guī)則:所有運(yùn)算子一律轉(zhuǎn)為數(shù)值,再進(jìn)行相應(yīng)的數(shù)學(xué)運(yùn)算。)
指數(shù)運(yùn)算符‘**’,這是第一次遇見,以前都是用Math.pow()來求冪的?。?!
發(fā)現(xiàn)兩者最大的區(qū)別在于編譯是99**99編譯時計算,Math.pow(99, 99)運(yùn)行時計算,具體說明參考“常量折疊”優(yōu)化技巧
‘**’指數(shù)運(yùn)算符是右結(jié)合,而不是左結(jié)合,如下:
2 ** 3 **2 // 512 相當(dāng)于 2**(3 ** 2)
關(guān)于相等和嚴(yán)格相等,這里的解釋是最令人通俗易懂的?。?!
‘==’比較的是兩個值是否相等;‘===’表比較它們是否為“同一個值”?!巴粋€值”也就是不僅要比較他們的值,還要比較它們的類型。
NaN與任何值都不相等(包括自身),正0等于負(fù)0(為什么,想不通)。
復(fù)合類型的數(shù)據(jù)比較,比較的是它們是否指向同一個地址。
null和undefined與自身嚴(yán)格相等,與其他類型的值比較時,結(jié)果都為false,它們互相比較時結(jié)果為true。
NaN == NaN // false +0 === -0 // true {} === {} // false {} == {} // false undefined === undefined // true null === null // true false == null // false false == undefined // false 0 == null // false 0 == undefined // false undefined == null // true
二進(jìn)制位運(yùn)算符實際中并不常用,所以并不怎么熟悉,但是我發(fā)現(xiàn)了一個有趣的東西,那就是異或運(yùn)算符^。
平時互換兩個變量的值,一般的做法是引入一個臨時變量temp,用來作為中間變量,但如果熟悉異或運(yùn)算符,可以進(jìn)行如下操作:
let a = 10; let b = 99; a ^= b, b ^= a, a ^= b; a // 99 b // 10 12.9 ^ 0 // 12 異或運(yùn)算也可以用來取整(“向下取整”,不能嚴(yán)格地說是向下取整)。 -12.9 ^ 0 // -12
數(shù)據(jù)類型轉(zhuǎn)換
強(qiáng)制轉(zhuǎn)換有三種Number()、String()和Boolean(),以前只會用Number(),不怎么常用后面兩種,常用toString()和!!代替前面兩個,也沒什么區(qū)別吧。
Number函數(shù)比parseInt函數(shù)嚴(yán)格很多,基本上只要有一個字符無法轉(zhuǎn)成數(shù)值,整個字符串就會被轉(zhuǎn)為NaN。parseInt逐個解析字符,而Number函數(shù)整體轉(zhuǎn)換字符串的類型。
關(guān)于Boolean(),除了undefined、null、0、NaN、"",五個值轉(zhuǎn)換結(jié)果為false,其他的值全部為true,包括空對象、空數(shù)組的轉(zhuǎn)換結(jié)果也為true。
parseInt("42 cats") // 42 Number("42 cats") // NaN Boolean(undefined) // false Boolean(null) // false Boolean(0) // false Boolean(NaN) // false Boolean("") // false Boolean({}) // true Boolean([]) // true Boolean(false) // false Boolean(new Boolean(false)) // true 因為這是一個對象
null轉(zhuǎn)為數(shù)值時為0,而undefined轉(zhuǎn)為數(shù)值時為NaN。
錯誤機(jī)制處理
每次出現(xiàn)報錯信息,都看不懂報錯的原因是為什么,終于可以讓我好好理解一下,因為什么原因會報錯了。
Error實例對象是最一般的錯誤類型,在它的基礎(chǔ)上,JavaScript還定義了其他6種錯誤對象,也就是說,存在Error的6個派生對象。
SyntaxError對象是解析代碼時發(fā)生的語法錯誤。
ReferenceError對象是引用一個不存在的變量時發(fā)生的錯誤。
RangeError對象是一個值超出有效范圍時發(fā)生的錯誤。
TypeError對象是變量或參數(shù)不是預(yù)期類型時發(fā)生的錯誤。
URIError對象是URI相關(guān)函數(shù)的參數(shù)不正確時拋出的錯誤。
EvalError對象是eval函數(shù)沒有被正確執(zhí)行時,拋出的錯誤,該錯誤類型已經(jīng)不再使用了,只是為了保證與以前代碼兼容,才繼續(xù)保留。
編程規(guī)范
不使用分號的三種情況
1、for和while循環(huán),注:do…while循環(huán)是有分號的;
2、分支語句:if,switch,try
3、函數(shù)的聲明語句,注:函數(shù)表達(dá)式仍然要使用分號。
for( ; ; ) { } while (true) { } // 沒有分號 do { a--; } while(a > 0); // 有分號 if (true) { } switch () { } try { } catch { } function f() { } // 沒有分號 let f = function f() { }; // 有分號
有一個重大的發(fā)現(xiàn),竟然可以用對象結(jié)果代替switch…case結(jié)構(gòu)?。?!
function doAction(action) { switch (action) { case "hack": return "hack"; case "slash": return "slash"; default: throw new Error("Invalid action."); } } // 變身后 function doAction(action) { let actions = { "hack": function () { return "hack"; }, "slash": function () { return "slash"; } }; if (typeof actions[action] !== "function") { throw new Error("Invalid action."); } return actions[action](); }
語法專題
真是沒想到console.log方法還支持占位符,可以像C語言一樣用于輸出不同類型的數(shù)據(jù)。
占位符有以下幾種:
%s 字符串
%d 整數(shù)
%i 整數(shù)
%f 浮點數(shù)
%o 對象的連接
%c CSS格式字符串(這個是最令我好奇的)
其他的有關(guān)console方法,感覺用處不是很大,其中有個console.count()感覺還是會用到的,count方法用于計數(shù),輸出它被調(diào)用了多少次。
function greet(user) { console.count(); return "hi " + user; } greet("bob") // default: 1 // "hi bob" greet("alice") // default: 2 // "hi alice"
標(biāo)準(zhǔn)庫
Object對象的原生方法分成兩類:
1)Object本身的方法(又稱為“靜態(tài)方法”):直接定義在Object對象的方法;
2)Object的實例方法:定義在Object原型對象Object.prototype上的方法,它可以被Obejct實例直接使用。
Object.print = function (o) { console.log(o) }; // 這個Object對象本身的方法,print方法直接定義在Object對象上 Object.prototype.print = function () { console.log(this); }; let obj = new Object(); obj.print() // Object 凡是定義在Object.prototype對象上面的屬性和方法,將被所有實例對象共享。
Object本身是一個函數(shù),如果參數(shù)是原始類型的值,Object方法將其轉(zhuǎn)為對應(yīng)的包裝對象的實例;如果Object方法的參數(shù)是一個對象,它總是返回該對象,即不用轉(zhuǎn)換。
let obj = Object(1); obj instanceof Object // true obj instanceof Number // true 包括number、string、boolean let arr = []; let obj = Object(arr); // 返回原數(shù)組 obj === arr // true 包括數(shù)組、對象、函數(shù) function isObject(value) { return value === Obejct(value); } // 可以用來判斷變量是否為對象(數(shù)組、對象、函數(shù))
Object構(gòu)造函數(shù)與直接賦值是等價的。
var o1 = {a: 1}; var o2 = new Object(o1); // 兩個對象指針指向同一個地址。 var o3 = new Object({a: 1}); // 不能這樣賦值哦,這樣賦值,重新分配了一個地址,就是一個全新的對象。 o1 === o2 // true 只適用于Object,數(shù)組不適用 o1 === o3 // false var obj = new Object(123); obj instanceof Number // true
通過Object.prototype.toString可以看出一個值到底是什么類型,其中返回值的第二個值表示該值的構(gòu)造函數(shù)。實例對象可能會自定義toString方法,覆蓋掉Object.propotype.toString方法,所以最要直接用Object.prototype.toString方法,并通過函數(shù)的call方法,可以在任意上調(diào)用這個方法。
Object.prototype.toString.call(2) // "[object Number]" Object.prototype.toString.call("") // "[object String]" Object.prototype.toString.call(true) // "[object Boolean]" Object.prototype.toString.call(undefined) // "[object Undefined]" Object.prototype.toString.call(null) // "[object Null]" Object.prototype.toString.call(Math) // "[object Math]" Object.prototype.toString.call({}) // "[object Object]" Object.prototype.toString.call([]) // "[object Array]" // **比typeof運(yùn)算符更準(zhǔn)確的類型判斷函數(shù)** var type = function (o){ var s = Object.prototype.toString.call(o); // *這里的正則表達(dá)式還需下點功夫,學(xué)會手動寫正則* return s.match(/[object (.*?)]/)[1].toLowerCase(); }; type({}); // "object" type([]); // "array" type(5); // "number" type(null); // "null" type(); // "undefined" type(/abcd/); // "regex" type(new Date()); // "date"
emmm接下來的屬性描述,平時不怎么接觸,對這一塊也很陌生,以后要多看看?。?!
for...in循環(huán):只有“可遍歷”的屬性,才會被for...in循環(huán)遍歷,包括繼承的屬性。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104859.html
摘要:在有了基礎(chǔ)之后,進(jìn)一步學(xué)習(xí)內(nèi)容包括框架。前端學(xué)習(xí)交流群禁止閑聊,非喜勿進(jìn)。代碼提交前必須做的三個事情檢查所有變更跑一邊單元測試手動運(yùn)行一遍所有 網(wǎng)站開發(fā)開發(fā)大致分為前端和后端,前端主要負(fù)責(zé)實現(xiàn)視覺和交互效果,以及與服務(wù)器通信,完成業(yè)務(wù)邏輯。其核心價值在于對用戶體驗的追求。可以按如下思路學(xué)習(xí)系統(tǒng)學(xué)習(xí): 基礎(chǔ)知識: html + css 這部分建議在?w3school 在線教程上學(xué)習(xí),邊...
摘要:在有了基礎(chǔ)之后,進(jìn)一步學(xué)習(xí)內(nèi)容包括框架。前端學(xué)習(xí)交流群禁止閑聊,非喜勿進(jìn)。代碼提交前必須做的三個事情檢查所有變更跑一邊單元測試手動運(yùn)行一遍所有 網(wǎng)站開發(fā)開發(fā)大致分為前端和后端,前端主要負(fù)責(zé)實現(xiàn)視覺和交互效果,以及與服務(wù)器通信,完成業(yè)務(wù)邏輯。其核心價值在于對用戶體驗的追求??梢园慈缦滤悸穼W(xué)習(xí)系統(tǒng)學(xué)習(xí): 基礎(chǔ)知識: html + css 這部分建議在?w3school 在線教程上學(xué)習(xí),邊...
摘要:在繼承的構(gòu)造函數(shù)中,我們必須如上面的例子那么調(diào)用一次方法,它表示構(gòu)造函數(shù)的繼承,與中利用繼承構(gòu)造函數(shù)是一樣的功能。 showImg(https://segmentfault.com/img/remote/1460000009078532); 在實際開發(fā)中,ES6已經(jīng)非常普及了。掌握ES6的知識變成了一種必須。盡管我們在使用時仍然需要經(jīng)過babel編譯。 ES6徹底改變了前端的編碼風(fēng)格,...
摘要:基于原型的面向?qū)ο笤诨谠偷恼Z言中如并不存在這種區(qū)別它只有對象不論是構(gòu)造函數(shù),實例,原型本身都是對象。允許動態(tài)地向單個的對象或者整個對象集中添加或移除屬性。為了解決以上兩個問題,提供了構(gòu)造函數(shù)創(chuàng)建對象的方式。 showImg(https://segmentfault.com/img/remote/1460000013229218); 一. 重新認(rèn)識面向?qū)ο?1. JavaScript...
摘要:基于原型的面向?qū)ο笤诨谠偷恼Z言中如并不存在這種區(qū)別它只有對象不論是構(gòu)造函數(shù),實例,原型本身都是對象。允許動態(tài)地向單個的對象或者整個對象集中添加或移除屬性。為了解決以上兩個問題,提供了構(gòu)造函數(shù)創(chuàng)建對象的方式。 showImg(https://segmentfault.com/img/remote/1460000013229218); 一. 重新認(rèn)識面向?qū)ο?1. JavaScript...
閱讀 1225·2021-09-26 09:55
閱讀 3191·2019-08-30 15:55
閱讀 965·2019-08-30 15:53
閱讀 2296·2019-08-30 13:59
閱讀 2380·2019-08-29 13:08
閱讀 1107·2019-08-29 12:19
閱讀 3302·2019-08-26 13:41
閱讀 418·2019-08-26 13:24