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