JS知識點整理(一)
前言
本文把平時的一些讀書筆記和理解進行了整理歸納,包含一些易混淆、遺漏的知識點,也會配上一些例子,可能不是很完整,還會有點雜,但也許會有你需要的(目前先整理了一部分,筆記有點多,後續會持續更新)。
一、變量
1.1 變量聲明
1.變量是常見的標識符,以字母、$、_開頭,但是不能包含+ - *等標識符,中文也是合法的標識符,保留字不能作為標識符。
2.函數聲明和賦值會分為兩個階段,一個是編譯階段的任務,就是編譯器聲明變量,另一個是執行階段的任務,就是js引擎去查詢賦值,所以聲明都會在代碼被執行前首先進行處理。
3.如果在函數中使用var定義一個變量,函數調用時相當於創建了這個變量並賦值,在函數退出後就會被銷毀,所以在函數外面讀不到這個變量。但是如果在函數內定義變量時不使用var,相當於是全局變量,外面一般是讀得到的,但是如果不運行這個函數時,相當於沒有創建這個變量,外面也是讀不到的:
function test(){
message = ‘hello‘
}
test(); // 如果不先運行這個,則讀不到message變量
alert(message);
4.var聲明的變量不能用delete刪除 ,delete可以刪除一個對象的屬性,但不能刪除繼承的屬性。
5.變量沒有類型,變量的值才有類型。
1.2 變量提升
1.提升是指聲明會被視為存在於其所出現的作用域的整個範圍內,就是說在哪個作用域聲明的,它就在這個作用域內(let, const並不會提升)。
2.函數聲明提升:
foo(); // typeError 相當於對undefined進行函數執行,所以是類型錯誤 bar(); // referenceError 不存在這個函數,所以是引用錯誤 var foo = function bar() {} // 函數表達式不會提升
3.函數提升的優先級大於變量提升的優先級,即函數提升在變量提升之上。
// 例一: var fo; fo = function(){ console.log(456); } function fo(){ console.log(123); } fo(); // 456 函數聲明被提升到了最上面,然後被後面的函數覆蓋 // 例二: fo = function(){ console.log(456); } fo(); // 456 同理,函數也是被覆蓋 var fo; function fo(){ console.log(123); } // 例三: var fo = function(){ console.log(456); } function fo(){ console.log(123); } fo(); // 456 同理,函數也是被覆蓋 // 同時函數聲明還能被後面的聲明覆蓋,說明越後面的函數聲明排在越後面,然後把前面的函數覆蓋了: foo(); // 3 function foo() { console.log(1); } var foo = function() { console.log(2); } function foo() { console.log(3); }
4.繼續例子
console.log(foo); // 打印出函數源碼
foo(); //可以執行 undefined 和 12
var foo=10;
foo(); //foo已經被賦值為一個變量,無法執行foo為函數,所以報錯
console.log(foo); // 上面報錯,這裏執行不到
function foo(){
var a;
console.log(a);
a=12;
console.log(a);
}
console.log(foo);
//以上實際執行順序:
function foo(){
var a;
console.log(a);
a=12;
console.log(a);
}
var foo;
console.log(foo);
foo();
foo=10;
foo(); //由於這裏報錯,foo已經被賦值,找不到這個函數,下面的都不會被執行
console.log(foo);
console.log(foo);
1.3作用域
1.31 全局/函數/塊作用域
1.作用域是一套規則(或者理解為約束範圍),用於確定在何處以及如何查找變量,其實也就是查找變量的地方。
2.每個環境中都有一個變量對象,所以該環境下定義的變量和函數都保存在這個對象中。
3.當代碼在一個環境中執行時,會產生作用域鏈,如函數的作用域鏈的第一個對象是arguments對象(arguments在全局中是不存在的),第二個對象是上一層環境,即該環境的外部環境,以此類推,全局對象是作用域鏈中的最後一個對象。
4.if和for中用var聲明的變量都是全局變量。
5.循環變量比較:
// 例一:
for(var i = 0; i < 3; i++) {
console.log(i); // 0 1 2
}
console.log(i); // 3
// 例二:
for(var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i); // 後面再輸出三次4
}, 0)
}
console.log(i); // 這個先輸出,為4
// 例三:
for(let i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i); // 1 2 3 let在每次叠代中都重新聲明
}, 0)
}
6.函數參數也是屬於函數局部作用域的,它們是隱式創建的。
7.塊作用域:
- ① with()可將代碼的作用域設置到一個特定的對象中。
- ② try/catch中catch也會創建塊作用域,err只能在該塊作用域中訪問。
- ③ let/const。
以上方式可將變量綁定在一個塊中,形成這個變量的塊作用域。
塊作用域還利於垃圾回收,方便引擎明確哪塊作用域的變量可以進行回收。
8.暫時性死區:
{
typeof a; // undefined 未聲明的反而不會報錯
typeof b; // referenceErroe 暫時性死區
let b;
}
1.32 詞法作用域
1.詞法作用域意味著作用域是由書寫代碼時函數聲明的位置決定的。
2.eval()和with()能欺騙詞法作用域,而且還會影響性能(因為js引擎不能事先確定變量和函數的定義位置,即不能進行詞法靜態分析)。
3.函數在哪裏調用沒有關系,變量的位置在編譯的詞法分析階段就確定了:
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo(); // 這裏其實就是閉包,包含了該函數的詞法作用域
}
bar(); // 1
// 函數調用位置更換:
bar(); // undefined 全局value雖然聲明了,但是在bar函數調用的後面才進行賦值,所以是undefined
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
1.4 條件語句
1.switch語句可判斷值、字符串、表達式等,且是全等比較,不會產生類型轉換(其實是===不允許進行類型轉換)。
2.其實沒有else if這個規範,其實真正是:
else{ // 省略了{}這個塊而已
if () {
} else {
}
}
3.switch:
// 例一:
switch(a){
case 1: // case不能放邏輯表達式,只能是常量表達式,即只能進行單一的===對比
// code
break;
case 2:
// code
break;
default:
// code
}
// 例二:
var b = ‘42‘;
switch(true){
case b == 2: // 要進行類型轉換比較則采取這種方式
// code
break;
case b == 42:
// code
break;
case b > 30: // 大小比較
// code
break;
default:
// code
}
// 例三:
var c = ‘42‘;
switch(c){
case 1:
case 2:
default:
console.log(‘default‘)
case 3:
console.log(‘3‘);
break;
case 4:
console.log(‘4‘)
}
// 會得到‘default‘ ‘3‘, 首先會遍歷所有的case,然後沒有符合的case,然後執行default,之後沒遇到break就繼續往下執行case 3,最後到break停止。
1.5循環遍歷
1.for循環中先把範圍值保存為變量,優化循環。
2.do while
do {
// code
} while (‘條件‘); // 記得加上後面的分號
3.遍歷對比:
自身:
- ① Object.keys返回對象自身的可枚舉屬性(數組)。
- ② Object.getOwnPropertyNames返回對象自身可枚舉和不可枚舉屬性(數組),如數組的length屬性。
- ③ hasOwnPropery()遍歷自身可枚舉和不可枚舉屬性。
自身和原型:
- ① in操作符能訪問自身和原型上的可枚舉和不可枚舉屬性。
- ② for in 能訪問自身和原型上的可枚舉屬性,不含不可枚舉屬性。
4.循環更改格式:[ [ {}, {} ,{} ], [ {}, {} ,{} ], [ {}, {} ,{} ] ] 如果要轉為[ [ ], [ ], [ ] ] 或者其他格式,可先用concat()方法把數組中的數組先循序連接起來,然後再用其他方法處理。
5.可以使用while來判斷循環,直到不滿足條件後才停止判斷運行,比for循環直觀方便,如:
while( i<5 ) { // i為大小不確定值
// code
i++;
}
6.中斷循環:forEach不能中斷,for可以。
7.break和continue:break能跳出循環,但也只能跳出一層循環,如果需要跳出多層循環,則需要使用標簽;continue能跳過本輪循環,繼續下輪循環:
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log(‘i=‘ + i + ‘, j=‘ + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// 標簽相當於定位符,用於跳轉到程序的任意位置,語式如下:
label:
二、數據類型
2.1數據類型
1.基本類型:number 、string、boolean、null、undefined、symbol。
引用類型:object (包含子類型function、array)。
typeof function a(){}; // ‘function‘
2.typeof 檢測能得到的類型:
- ①"undefined" —— 如果這個值沒有定義
- ②"boolean" —— 如果這個值是布爾值
- ③"object" —— 如果這個值是對象或者null
- ④"string" —— 如果這個字是字符串
- ⑤"number" —— 如果這個值是數字
- ⑥"function" —— 如果這個值是函數
- ⑦"symbol" —— ES6引入的一種新的原始數據類型Symbol,表示獨一無二的值
2.2 Number
1.JavaScript 語言的底層根本沒有整數,所有數字都是小數(64位浮點數)。
2.在JavaScript內部,整數和浮點數是同樣的儲存方法,所以3和3.0被視為同一個值:
3.0 === 3; // true
3.數字的二進制浮點數沒那麽精確:
0.1 + 0.2 === 0.3; // false
4.數字範圍:2的1024次方到2的-1023次方。
5.最大的安全整數:2^53。
6.parseInt方法用於將字符串轉為整數。如果parseInt的參數不是字符串,則會先轉為字符串再轉換。字符串轉為整數的時候,是一個個字符依次轉換,如果遇到不能轉為數字的字符,就不再進行下去,返回已經轉好的部分。而isNaN是先將整體參數轉化為number再進行判斷:
parseInt(‘abc‘); // NaN
parseInt(‘.3‘); // NaN
parseInt(‘‘); // NaN
parseInt(‘+‘); // NaN
parseInt(‘+1‘); // 1
parseInt(‘1000‘, 2); // 8 可接受第二個進制參數
7.toFixed註意事項:
typeof 12.236.toFixed(2); // ‘string‘ 指定保留位數後數字變成了字符串
42.toFixed(3); // 會報錯,因為會把小數點算為42的一部分,需要用使用以下方式:
(42).toFixed(3);
42.0.toFixed(3)
42..toFixed(3)
8.判斷是否為整數:
// 方式一:
typeof a === ‘number‘ && num%1 === 0
// 方式二:
Number.isInteger(a);
// 方式三:
Number.isSafeInteger(a);
9.NaN:
NaN === NaN // false
NaN !== NaN // true
Boolean(NaN) // false
typeof NaN // ‘number‘
// 判斷是否為NaN:
// 原生方式:
Number.isNaN(n);
// 自定義方式:
function isNaN(n) {
return n !== n;
}
2.3 String
1.字符串可使用方括號[ ]來獲取該位置上的字符,也可查詢長度,但無法像數組一樣增加或刪除字符。
2.數字字符串轉數字的一種方式:字符串與1想乘:"2" * 1
3.數字轉字符串的一種方式:數字加空字符串: 1 + ""
4.拆分:
‘a b c‘.split(‘ ‘);
// [‘a‘, ‘b‘, ‘‘, ‘‘, ‘c‘] b和c之間有三個空格,所以三個空格會得到夾著的兩個空格。
5.字符串沒有map()、join()等方法,但可以通過Array.prototype.call()來借用,reverse()不可借用,可先轉為數組再使用。
6.截取:
①substring() :
參數如果是負數,會變為0,如果第一個參數大於第二個參數,則會調換位置。②substr():
第一個參數是開始位置,第二個是長度,如果第一個參數是負數,則表示倒數計算的字符位置,如果第二個參數是負數,則返回空字符串(相當於返回長度為0)。③match():
用於確定原字符串是否匹配某個子字符串,返回一個數組,成員為匹配的第一個字符串。如果沒有找到匹配,則返回null。④search():
search方法的用法基本等同於match,但是返回值為匹配的第一個位置。如果沒有找到匹配,則返回-1。
2.4 Boolean
1.六個false值:“”,null, undefined, 0, NaN,false。
2."‘‘"不是空字符串,是true。
3.document.all是ie中的假值對象,是false。
2.5 Null和Undefined
1.null和undefined的名稱既是類型也是值,null指空值,曾賦過值,但目前為沒有值,undefined指沒有值,未賦值。
2.null是js中的一個bug,因為不同的對象在底層都表示為二進制,在js中二進制前三位都為0時就判斷為object類型,而null的二進制表示是全0,所以執行typeof時會得到‘object’(或者把null當成一個空對象指針,所以typeof檢測會得到object)。
3.null==undefined 是true,且不進行類型轉換,因為它們是類似的值,且只有null和undefined是==,和其它對比都是false,所以:
null == 0 // false
undefined == 0 // false
null == ‘‘ // false
undefined == ‘‘ // false
null == fasle // false
undefined == false // fasle
// 只有自身轉化才會是布爾值:
!null == true // true
!undefined == true // true
// 但運算時,null會轉型為0,undefined轉為NaN:
null + 3 // 3
undefined + 3 // NaN
// 判斷類型:
typeof null // ‘object‘
typeof undefined // ‘undefined‘
2.6 廣義Object
2.6.1 狹義對象
1.所有的對象都是繼承自Object的,都會帶有這些屬性,toString(), valueOf(), constructor。
2.創建對象 :
// ①字面量方式:
var o = {};
// ②Object.create方式:
Object.create(‘這個對象的原型,對象屬性的描述‘)
Object.create({x:1,y:2}) // 繼承了這個對象的屬性
Object.create(null) // 則不會繼承任何屬性和方法;
Object.create(Object.prototype) // 和new Object()一樣創建了一個空對象
// ③構造函數方式:
function createPerson (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
alert(this.name);
}
}
// ④工廠模式方式:
function createPerson (name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
alert(this.name);
}
return o;
}
構造函數與工廠模式區別:
- ①沒有顯示的創建對象。
- ②直接將屬性和方法賦予給了this對象。
- ③沒有return語句。
構造函數過程:
- ①創建一個空對象。
- ②將構造函數的作用域賦給空對象(this指向空對象,空對象原型指向構造函數原型)。
- ③執行代碼(為這個空對象添加屬性)。
- ④返回新對象(return this)。
構造函數之所以叫“構造函數”,就是說這個函數的目的,就是操作一個空對象(即this對象),將其“構造”為需要的樣子。構造函數中如果有return一個對象,則new這個構造函數時得到的是這個對象,而不是新的this對象(可以認為構造函數內開頭先定義了一個this變量,然後最後返回this)。
構造函數內的方法在每次生成實例的時候,實例對象內的函數都是新生成的,相當於new了一個函數,因為函數也是對象,所以每次生成實例對象內的函數的時候,就相當於定義了一個對象,所以雖然它們名字相同,但卻是不同的函數。
// o指對象,返回的就是對象本身
o.valueOf() === o // true
// 數組也是如此,因為數組也是對象,也可以用構造器生成:
var a = new Array()
// 就像構造函數創建對象,所以a也會帶有toString等屬性,因為對象都會繼承toString等方法。
4.訪問對象屬性:如果對象的屬性是動態、不可預測或不符合變量規範的,用方括號的形式person["name"],而不能用點.方式,方括號內要放字符串,但當name是變量時,也可以用person[name]來訪問屬性。
5.檢測屬性:
- ①
in
// 檢測屬性是否存在於自身或原型上,含不可枚舉屬性 - ②
hasOwnProperty()
// 檢測屬性是否存在於自身,含不可枚舉屬性 - ③
propertyIsEnumerable()
// 檢測屬性是否存在於自身,不含不可枚舉屬性
6.對象轉換:
// ①Object()可將任何值轉為對象;Object()返回一個空對象;如果Object方法的參數是一個對象,它總是返回該對象:
var value = {};
var obj = Object(value) // 返回原對象
obj === value // true
// ②valueOf返回一個對象的“值”,默認情況下返回對象本身:
var obj = new Object();
obj.valueOf() === obj // true
// ③new Object(value)的值是value對象。
var o1 = new Object();
o1.toString() // "[object Object]" 註意大小寫
數組、字符串、函數、Date 對象都分別部署了自定義的toString方法,覆蓋了原生的Object.prototype.toString方法,原生的Object.prototype.toString()返回的是類:
// 數組:
[1, 2, 3].toString(); // "1,2,3"
// 字符串:
‘123‘.toString(); // "123"
// 函數:
(function () { return 123;}).toString(); // "function () { return 123; }"
// Date:
(new Date()).toString(); // "Tue May 10 2016 09:11:31 GMT+0800 (CST)"
8.對象是引用同一個地址:
var o1 = {};
var o2 = o1;
o1 = 1; // o1是改變了自己的指向,而不是改變{}
o2; // {} o2已指向{}的地址,只要這個地址的對象沒有變,它就不會變
原始類型是值拷貝:
var x = 1;
var y = x;
x = 2;
y // 1
深拷貝:
// 方式一:
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
// 方式二:
function deepCopy (p, c) {
c = c || {};
for (let i in p) {
if (p.hasOwnProperty[i]) { // 排除繼承屬性
if (typeof p[i] === ‘object‘) {
c[i] = Array.isArray(p[i]) ? [] : {};
deepCopy[p[i], c[i]];
} else {
c[i] = p[i];
}
}
}
return c;
}
9.對象屬性描述符:
// configurable 能否修改屬性
// enumerable 是否可枚舉
// writable 能否修改屬性的值
// value 屬性的數據值
var myObject = { a: ‘2‘ };
var b = Object.getOwnPropertyDescriptor(myObject, ‘a‘);
console.log(b); // {value: "2", writable: true, enumerable: true, configurable: true}
Object.defineProperty(myObject, ‘a‘, {
value: ‘3‘,
writable: true, // 可修改
enumerable: true, // 可枚舉
configurable: true // 可配置,如果為false,則不能修改以上配置,但可以//myObject.a= 5, writable可以變為false, 但不能變為true
})
10.get set
var other = {
get a(){
return this._a_;
},
set a(val){
this._a_ = val*2;
}
}
console.log(other); // {}
console.log(other.a); // undefined
other.a = 2;
console.log(other.a); // 4
11.Function.prototype是一個函數,RegExp.prototype是一個正則表達式,Array.prototype是一個數組,它們都是空的,(但總的來說它們都是對象)。
12.字符串要訪問屬性或方法時,js會自動將其轉化包裝對象,這種讓js自行執行,而不要人為轉為包裝對象,否則會影響性能。
‘abc‘.length // 3
2.6.2 函數
1.函數中執行return語句後立刻退出,所以放在return語句後面的語句不會執行;未指定返回值的函數返回的是undefined。
2.函數的參數在內部是用數組來表示的,arguments是類數組,可用arguments[0]來獲取參數,arguments的長度是由傳入的參數個數決定的,而不是由命名參數的個數決定的;參數傳遞的都是值,傳入引用類型值時註意是否有影響。
3.函數名稱和參數長度:a.name , a.length是預期傳入的參數個數,不是實際參數個數。
4.沒有函數簽名,所以沒有重載,即同名函數會被後面發覆蓋,但是能通過判斷參數的類型和數量來作出不同的反應來模仿方法的重載。
5.函數實際上是對象,每個函數都是Function類型的實例,而且和其他應用類型一樣具有屬性和方法,如call、apply、length、contructor、prototype、name等屬性,函數名實際上是指向函數對象的指針。
6.區分函數聲明和表達式的方法是看function出現在聲明的哪個位置,如果function是第一個詞,就是函數聲明,否則為函數表達式(自執行函數是以括號開頭,所以為表達式)。
7.函數內有兩個特殊的對象:
①arguments:
arguments有一個callee屬性,是一個指針,指向擁有這個arguments對象的函數。② this:
this引用的是函數據以執行的環境對象。
8.一些區別:
①函數聲明:
function a() {}
可直接a()調用,花括號後面不用分號結尾。- ②函數表達式:
let t = function() {}
可用t()調用,且一般不帶函數名,如果加上函數名,該函數名只在函數體內部有效,在函數體外部無效,花括號後面帶分號:
var print = function x(){
console.log(typeof x);
}
x; // ReferenceError: x is not defined
print(); // function
- ③構造函數:
var add = new Function(
‘x‘,
‘y‘,
‘return x + y‘
)
// 等同於
function add(x, y) {
return x + y;
}
- ④函數執行時所在的作用域,是定義時的作用域,即詞法作用域,而不是調用時所在的作用域:
var a = 1;
var x = function () {
console.log(a);
}
function f() {
var a = 2;
x();
}
f(); // 1
9.原生函數:
- Number(), String(), Boolean(),
- Object(), Array(), Function(),
- RegExp(), Date(), Error(), Symbol()
10.類型判斷:
var a = new String(‘abc‘);
typeof a; // ‘object‘ a為包裝對象
a instanceof String // true
Object.prototype.toString(a); // ‘[object, Object]‘ 如果不使用call,不論傳入什麽,都為Object類,這個沒什麽用,如果要用於判斷類型,都得加call
Object.prototype.toString.call(a); // ‘[object, String]‘ 讓a調用Object上的toString方法,屬於String類
11.返回
return ( // return如果有換行,需要加括號
a*2;
)
12.如果構造函數內部有return語句,而且return後面跟著一個對象,new命令會返回return語句指定的對象;否則,就會不管return語句,返回this對象:
// 例一:
var Vehicle = function (){
this.price = 1000;
return { price: 2000 };
}
(new Vehicle()).price; // 2000 如果不使用new,則this將變為全局的
// 例二:如果對普通函數(內部沒有this關鍵字的函數)使用new命令,則會返回一個空對象:
function getMessage() {
return ‘this is a message‘;
}
var msg = new getMessage();
msg // {}
typeof msg // "object"
2.6.3 數組
1.可通過設置數組的長度對數組進行增加或刪減元素,也可以為數組添加字符串鍵,但不會算入數組長度(數字字符串除外),如:a[‘13‘] = ‘test‘
2.檢測是否為數組的兩種方法:
- ①value instanceof Array
- ②Array.isArray(value)
3.對數組調用toString()方法時返回每個值的字符串以逗號連接起來的字符串,alert()接受的是字符串參數,所以:
var people=[per1,per2];
alert(people.valueOf());
// 返回的還是以逗號連接的字符串,因為會默認調用後臺的toString()方法將people轉為字符串
4.value.join("|"),不傳參時默認以逗號連接。
5.返回值:
- push()、unshift()返回的是修改後的數組的長度
- pop()、shift()返回的是刪除的項
6.sort()是高階函數,可傳入方法:
var arr = [2, 10, 20, 1];
arr.sort(function (x, y) { // 升序
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
return 0;
});
console.log(arr); // [1, 2, 10, 20]
//或者
function(x, y){
return x - y; // 升序
}
7.棧與隊列:
- 棧方法:LIFO(last-in-first-out)後進先出push()和pop()。
- 隊列方法:FIFO(first-in-first-out)先進先出push()和shift()。
8.數組原始值是否改變:
不改變原數組:(連接\截取\循環)
- concat:連接多個數組,返回新的數組
- join:將數組中所有元素以參數作為分隔符放入一個字符
- slice:slice(start,end),返回選定元素
- map,filter,forEach,some,every等不改變原數組
改變原數組:(增加\刪除\換序)
- shift:將第一個元素刪除並且返回刪除元素,空即為undefined。
- unshift:向數組開頭添加元素,並返回新的長度。
- pop:刪除最後一個並返回刪除的元素。
- push:向數組末尾添加元素,並返回新的長度。
- reverse:顛倒數組順序。
- sort:對數組排序。(數組排序後和與排序前的數組絕對相等===,因為還是同一個引用)
- splice: splice(start,length,item)刪,增,替換數組元素,返回被刪除數組,無刪除則不返回,如果只提供第一個參數,等同於將原數組在指定位置拆分成兩個數組:
var a = [1, 2, 3, 4];
a.splice(2); // [3, 4]
a; // [1, 2]
9.delete刪除數組元素,不會改變數組長度,該位置會變空為undefined。
10.類數組轉數組:因為slice內部返回的是新建的數組(使用循環取值):
Array.prototype.slice.call({ 0: ‘a‘, 1: ‘b‘, length: 2 }) // [‘a‘, ‘b‘]
Array.prototype.slice.call(document.querySelectorAll("div"));
Array.prototype.slice.call(arguments);
11.reduce():
- 一參:累積變量,默認為數組的第一個成員
- 二參:當前變量,默認為數組的第二個成員
- 三參:當前位置(從0開始)
- 四參:原數組
應用:找出最長字符串:
function findLongest(entries) {
return entries.reduce(function (longest, entry) {
return entry.length > longest.length ? entry : longest;
}, ‘‘);
}
findLongest([‘aaa‘, ‘bb‘, ‘c‘]); // "aaa"
12.數組去重:
let s = new Set([1, 2, 3, 3, ‘3‘]);
s; // Set {1, 2, 3, "3"}
let arr = [..s];
let arrs = [‘apple‘, ‘strawberry‘, ‘banana‘, ‘pear‘, ‘apple‘, ‘orange‘, ‘orange‘, ‘strawberry‘];
arrs.filter(function (element, index, self) {
return self.indexOf(element) === index;
})
13.空單元數組:
// 例一:
var arr = ["a", "b", "c"];
console.log(arr[‘2‘]); // ‘c‘
arr[‘5‘] = ‘e‘;
console.log(arr.length); // 6
console.log(arr); // ["a", "b", "c", empty × 2, "e"]
// 例二:
var a = new Array(3);
console.log(a); // [empty × 3] 空單元數組
var b = [undefined,undefined,undefined]; // 這個不是空單元數組,是值為undefined的數組
// 例三:
var c = [];
c.length = 3;
console.log(c); // [empty × 3] 空單元數組
14.數組和字符串都有的方法:splice()、indexOf()、lastIndexOf()、contact()
2.7 類型轉換
1.toString()轉換為字符串,如果是數字,可傳遞基數來確認返回的是多少進制的數字字符串:
let num = 12;
num.toString(8) // 返回8進制字符串
2.alert
會調用對象的toString()
方法,alert(a)
和alert(a.toString())
是一樣的。
3.對象轉化:
①對象轉數字默認先調用toValue()方法,如果返回的不是原始值,則再調用toString()方法。
②對象轉字符串默認先調用toString()方法,如果返回的不是原始值,則再調用toValue()方法。
③日期對象轉數字時會默認直接調用toString()方法。
4.null和undefined沒有toString()方法,但是可以使用String()來將它們轉為字符串。
5.Number轉化:
Number({}); // NaN
Number({a: 1}); // NaN
Number([1, 2, 3]); // NaN
Number([]); // 0
Number([5]); // 5
String([]); // ""
6.使用:
var a;
typeof a; // undefined
typeof b; // undefined 盡管沒聲明b,但不報錯,但如果使用b,則會報錯
var c = {};
c.a // undefined 訪問不存在的對象屬性不會報錯,所以也不能根據c.a===undefined來判斷是否有a屬性。
7.數組的toString方法(即Array.prototype.toString())被重新定義過,將所有單元字符串後用逗號連接起來,而原生的Object.prototype.toString()返回的是“類”。
var a = [1, 2, 3];
Object.prototype.toString(a); // "[object Object]" 返回“類”
console.log(a.toString()); // ‘1,2,3‘ 會先找到Array上的toString方法
console.log(Array.prototype.toString.call(a)); // ‘1,2,3‘ 讓a調用Array上的toString方法
console.log(Object.prototype.toString.call(a)); // [object Array] 讓a調用Object上的toString方法
8.JSON.stringify()可以將對象轉化為字符串,但它本質上是如果對象中有toJSON方法就先調用toJSON方法將所要轉化的對象換為安全的JSON值,把循環引用類型、函數、null、undefined等不符合json的值過濾掉,然後再交由toString方法來轉化。
JSON.stringify()還可接受數組參數或函數參數,作用和toJSON類似,用於過濾對象:
var a = {
b: 42,
c: ‘36‘,
d: [1,2,3]
};
JSON.sringify(a, ["b", "c"]); // "{"b":42, "c":"36"}"保留傳入數組中包含的對象屬性
JSON.stringify(a, function(k, v) {
if (k !== "c"){
return v;
}
}) // "{"b":42, "d":[1,2,3]}"
9.parseInt:
parseInt(new String(42)) // 42 是數字
因為parseInt是針對字符串的,所要parseInt會先調用所傳入參數的toString方法將參數轉化為字符串,然後再解析數字。
10.在存在布爾值中使用==或===進行比較,或數字與字符串比較時,都是先將不是數字的那方先轉換為數字(轉為數字的優先級:布爾值>對象>字符串>數字),然後再進行比較:
var a = ‘123‘;
var b = true;
a == b; // false
//因為123不等於1,會先將布爾值轉為1,然後和‘123‘比較,然後將‘123‘轉為123再進行最後比較,所以“存在”和“==true”是不一樣的,比如:
var a = ‘42‘;
// if(a) 和 if(a==true) 不一樣。
11.進行算數運算時,優先調用valueOf()方法來轉化數字,如果未轉化成原始類型,則再調用toString()方法,但是Data對象是優先調用toString()方法。
最後
因為比較多,所以目前只整理到這裏,後續有些比較重要難懂的模塊會分開更新,希望對你有所幫助,如有不合理的地方歡迎指正,最後順口廣告來一波:大家好!我是BetterMan, to be better, to be man, better關註BetterMan!
JS知識點整理(一)