你可能遺漏的JS知識點(二)

前言

這是對平時的一些讀書筆記和理解進行整理的第二部分,第一部分請前往:你可能遺漏的JS知識點(一)。本文包含一些易混淆、遺漏的知識點,也會配上一些例子,也許不是很完整,也許還會有點雜,但也許會有你須要的,後續會持續更新,喜歡就關注一下嘍!html

3、運算符

3.1運算符

1.易忽略的例子:git

let obj = { x: 1, y: 2};
"toString" in obj;   //true obj繼承了toString()方法且in能遍歷原型上的不可枚舉屬性

let arr =[ 3, 6 ,8];
"0" in arr;          //true 數組包含有0索引屬性
複製代碼

2.運算子的不一樣,致使了不一樣的語法行爲,這種現象稱爲「重載」(overload)。加號會發生重載,由於加號可當成加法運算,也可做爲字符串鏈接符,而減法,除法和乘法不會發送重載,由於都是做爲數學運算使用。github

3.餘數運算符(%)的運算結果的正負號由第一個運算子的正負號決定:正則表達式

-1 % 2     // -1
1 % -2     // 1
10 % 0     // NaN
10 % '0'   // NaN
10 % 1     // 0
2 % 3      // 2
複製代碼
  • with:用於設置代碼在特定對象中的做用域。express

  • eval:可計算某個字符串,並執行其中的的 JavaScript 代碼。數組

  • void:做用是執行一個表達式,而後不返回任何值,或者說返回undefined。app

  • 逗號運算符:用於對兩個表達式求值,並返回後一個表達式的值。dom

'a', 'b'   // "b"

var x = 0;
var y = (x++, 10);
x;        // 1
y;        // 10
複製代碼

5.優先級:!> && > || > 三目運算符,等號優先級較低,逗號優先級更低。函數

//例一:
true || false && false  

//至關於: 
 true || (false && false)    // true

//例二:
var a = 42, b;
b = (a++, a);    // 由於括號包了起來,優先級比=高,因此優先運算括號內的結果,先a++,而後再a,獲得結果後再賦值給b
a;    // 43
b;    // 43
複製代碼

6.三目運算符可適當代替if else。post

4、內置對象

4.1 Date

1.Date對象是JavaScript原生的時間庫。它以1970年1月1日00:00:00做爲時間的零點,能夠表示的時間範圍是先後各1億天(單位爲毫秒),是構造函數。

2.直接調用Date老是返回當前時間,爲字符串,且傳入參數無效:

Date();   // "Wed Feb 19 2018 16:57:42 GMT+0800 (中國標準時間)"
Date(2000, 1, 1);   // "Wed Feb 19 2018 16:57:42 GMT+0800 (中國標準時間)"
複製代碼

3.new Date()返回當前日期,爲對象,也可接受多種格式的參數,返回一個該參數對應的時間實例:

  • ①不傳入參數:
new Date();   // Wed Dec 19 2018 17:03:59 GMT+0800 (中國標準時間)
複製代碼
  • ②參數爲時間零點開始計算的毫秒數:
new Date(1378218728000);   // Tue Sep 03 2013 22:32:08 GMT+0800 (中國標準時間)
複製代碼
  • ③參數也可爲負整數,表明1970年元旦以前的時間:
new Date(-1378218728000);   // Fri Apr 30 1926 17:27:52 GMT+0800 (中國標準時間)
複製代碼
  • ④參數爲多個整數,表明年、月、日、小時、分鐘、秒、毫秒:
new Date(2018, 0, 1, 0, 0, 0, 0);  // Mon Jan 01 2018 00:00:00 GMT+0800 (中國標準時間)
複製代碼
  • ⑤參數爲日期字符串,能夠以空格隔開或者逗號隔開,能夠2018,1,2順序或者1,2,2018順序,若是輸入數值不規範,會自動溢出,如2月沒有30號,會自動溢出爲3月1號:
new Date('January 6, 2018');   // Sat Jan 06 2018 00:00:00 GMT+0800 (中國標準時間)
複製代碼
  • ⑥只要是能被Date.parse()方法解析的字符串,均可以看成參數:
new Date('2018-2-15')
new Date('2018/2/15')
new Date('02/15/2018')
new Date('2018-FEB-15')
new Date('FEB, 15, 2018')
new Date('FEB 15, 2018')
new Date('Feberuary, 15, 2018')
new Date('Feberuary 15, 2018')
new Date('15 Feb 2018')
new Date('15, Feberuary, 2018')
// Thu Feb 15 2018 00:00:00 GMT+0800 (中國標準時間)
複製代碼

4.Date.now():

//Date.now方法返回當前時間距離時間零點(1970年1月1日 00:00:00 UTC)的毫秒數
Date.now()  // 1545211158395

Date.now() === new Date().getTime()   // true
複製代碼

5.Date.parse()

Date.parse方法用來解析日期字符串,返回該時間距離時間零點(1970年1月1日 00:00:00)的毫秒數:

Date.parse('Aug 9, 2018')
Date.parse('January 26, 2018 13:51:50')
Date.parse('Mon, 25 Dec 2018 13:30:00 GMT')
Date.parse('Mon, 25 Dec 2018 13:30:00 +0430')
Date.parse('2018-10-10')
Date.parse('2018-10-10T14:48:00')
複製代碼

6.數據接口通常使用時間戳,由於時間戳在哪一個時區都是同樣的。

7.能夠將日期的內部表達形式當成一個整數類型的timestamp, 而其餘的表達形式只不過是這種內部形式的‘糖衣’,因此new Date()實例的valueOf()返回的是一個timestamp就很容易理解了:

new Date().valueOf();    // 1542004695697
// 因此new Date()轉換爲整型只須要一個加號+,由於會自動調用valueOf()方法。

//以上等同於如下方式:
var d = new Date();
d.valueOf();     // 1542004695697 
d.getTime();    // 1542004695697 
Date.parse(d);  // 1542004695697 
Date.now();     // 1542004695697 
複製代碼

8.get方法:

  • getTime():返回實例距離1970年1月1日00:00:00的毫秒數,等同於valueOf方法。
  • getYear():返回距離1900的年數。
  • getFullYear():返回四位的年份。
  • getMonth():返回月份(0表示1月,11表示12月)。
  • getDate():返回實例對象對應每月的幾號(從1開始)。
  • getDay():返回星期幾,星期日爲0,星期一爲1,以此類推。
  • getHours():返回小時(0-23)。
  • getMinutes():返回分鐘(0-59)。
  • getSeconds():返回秒(0-59)。
  • getMilliseconds():返回毫秒(0-999)。
  • getTimezoneOffset():返回當前時間與 UTC 的時區差別,以分鐘表示,返回結果考慮到了夏令時因素。

9.set方法:

  • setTime(milliseconds):設置毫秒時間戳。
  • setYear(year): 設置距離1900年的年數。
  • setFullYear(year [, month, date]):設置四位年份。
  • setMonth(month [, date]):設置月份(0-11)。
  • setDate(date):設置實例對象對應的每月的幾號(1-31),返回改變後毫秒時間戳。
  • setHours(hour [, min, sec, ms]):設置小時(0-23)。
  • setMinutes(min [, sec, ms]):設置分鐘(0-59)。
  • setSeconds(sec [, ms]):設置秒(0-59)。
  • setMilliseconds():設置毫秒(0-999)。
var d = new Date();

// 將年份設爲去年:
d.setFullYear(d.getFullYear() - 1);

// 將日期向後推1000天:
d.setDate(d.getDate() + 1000);

// 將時間設爲6小時後:
d.setHours(d.getHours() + 6);
複製代碼

10.UTC時間比北京時間晚8小時。

4.2 Math

1.Math是 JavaScript 的原生對象,提供各類數學功能。該對象不是構造函數,不能生成實例,全部的屬性和方法都必須在Math對象上調用。

2.Math.random()獲得的是包括0但不包括1的隨機數。

  • ①取隨機數: [2, 10)
Math.random() * 8 + 2;    // 由於至少是大於或等於2,因此要加上2,同時又不能大於10,因此只能乘上8來保證小於8,而後加上2獲得小於10的數
複製代碼
  • ②取隨機數:(2, 10]
function f() {
    let a = Math.random() * 8 + 2, b;
    b = 12 - a; // a確定是一個大於等於2但小於10的數,因此b爲大於2但小於等於10的數
    return b;
}
f();  // 8.199542416221309
複製代碼
  • ③取隨機數:(2, 10)
function getNumber() {
    let a = Math.random(), b = 2, c;
    while(a === 0){
        a = Math.random();
    }
    c = a * 8 + b;
    return c;
} 
getNumber();   // 6.153494475244344
複製代碼
  • ④取隨機整數: [2, 10]的整數
Math.floor(Math.random() * 9 + 2);   // 乘以個數再加上第一個數(第一個可能的值)
// 加2保證了至少等於2,而隨機數乘9能獲得不到於9的數,而後二者相加取整後能保證最大就是10
複製代碼

3.Math.max()

  • ①取最大數:
Math.max.apply(null, [1,2,3]); 
複製代碼
  • ②確保一個合法的月份值:
Math.max(Math.min(1, 'input輸入值若是不在1-2的範圍內'), 12);
複製代碼

4.3 RegExp

1.全稱:regular expression。

2.修飾符:g, i, m, u, y

3.元字符:

  • ①點字符.匹配除回車(\r)、換行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)之外的全部字符。
  • ^表示字符串的開始位置。 /^test/.test('test123'); // true
  • $表示字符串的結束位置。 /test$/.test('new test'); // true
  • ④豎線符號|在正則表達式中表示"或關係"(OR)。 /11|22/.test('911') // true

4.量詞符:用來設定某個模式出現的次數。

  • ?問號表示某個模式出現0次或1次,等同於{0, 1}
  • *星號表示某個模式出現0次或屢次,等同於{0,}
  • +加號表示某個模式出現1次或屢次,等同於{1,}
// t 出現0次或1次
/t?est/.test('test')  // true
/t?est/.test('est')   // true

// t 出現0次或屢次
/t*est/.test('test')  // true
/t*est/.test('ttest') // true

// t 出現1次或屢次
/t+est/.test('test')  // true
/t+est/.test('ttest') // true
/t+est/.test('est')   // false
複製代碼

5.轉義符: 須要反斜槓轉義的一共有12個字符:^、.、[、$、(、)、|、*、+、?、{、\\

6.特殊字符:

  • [\b] 匹配退格鍵(U+0008),不要與\b混淆
  • \n 匹配換行鍵
  • \r 匹配回車鍵
  • \t 匹配製表符 tab(U+0009)
  • \v 匹配垂直製表符(U+000B)
  • \f 匹配換頁符(U+000C)
  • \0 匹配null字符(U+0000)

7.字符類: 要放到方括號內纔有效,字符類(class)表示有一系列字符可供選擇,只要匹配其中一個就能夠了,好比[xyz] 表示x、y、z之中任選一個匹配。

/[abc]/.test('hello world')   // false
/[abc]/.test('apple')         // true
複製代碼

①脫字符^:必定是要放到方括號內,要和元字符^區分開,若是方括號內的第一個字符是[^],則表示除了字符類之中的字符,其餘字符均可以匹配:

/[^abc]/.test('hello world')   // true
/[^abc]/.test('bbc')           // false
複製代碼

②連字符-:用來提供簡寫形式,表示字符的連續範圍。

/a-z/.test('b')     // false
/[a-z]/.test('b')   // true
複製代碼

8.重複類:使用大括號{}表示,{n}表示剛好重複n次,{n,}表示至少重複n次,{n,m}表示重複很多於n次,很少於m次。

/lo{2}k/.test('look')       // true
/lo{2,5}k/.test('looook')   // true
複製代碼

9.預約義模式:指的是某些常見模式的簡寫方式。

  • \d 匹配0-9之間的任一數字,至關於[0-9]
  • \D 匹配全部0-9之外的字符,至關於[^0-9]
  • \w 匹配任意的字母、數字和下劃線,至關於[A-Za-z0-9_]
  • \W 除全部字母、數字和下劃線之外的字符,至關於[^A-Za-z0-9_]
  • \s 匹配空格(包括換行符、製表符、空格符等),相等於[ \t\r\n\v\f]
  • \S 匹配非空格的字符,至關於[^ \t\r\n\v\f]
  • \b 匹配詞的邊界
  • \B 匹配非詞邊界,即在詞的內部
// 例:
/\s\w*/.exec('hello world');    // [" world"]

/\bworld/.test('hello world');  // true
/\bworld/.test('hello-world');  // true
/\bworld/.test('helloworld');   // false

/\Bworld/.test('hello-world');  // false
/\Bworld/.test('helloworld');   // true
var html = "<b>Hello</b>\n<i>world!</i>";

/[\S\s]*/.exec(html)[0];      // "<b>Hello</b>\n<i>world!</i>"  [\S\s]指代一切字符
複製代碼

①貪婪模式:默認狀況下都是最大可能匹配,即匹配直到下一個字符不知足匹配規則爲止。這被稱爲貪婪模式。

var s = 'aaa';
s.match(/a+/) ;  // ["aaa"]
複製代碼

②非貪婪模式:

  • *?:表示某個模式出現0次或屢次,匹配時採用非貪婪模式。
  • +?:表示某個模式出現1次或屢次,匹配時採用非貪婪模式。
var s = 'aaa';
s.match(/a+?/) ;  // ["a"];
複製代碼

11.組匹配:

/fred+/.test('fredd');       // true
/(fred)+/.test('fredfred');  // true

var m = 'abcabc'.match(/(.)b(.)/);
m;   // ['abc', 'a', 'c']

// 能夠用\n引用括號匹配的內容,n是從1開始的天然數,表示對應順序的括號:
/(.)b(.)\1b\2/.test("abcabc");    // true
/y((..)\2)\1/.test('yabababab');  // true   \1指向外層括號,\2指向內層括號
複製代碼

12.正則的實例方法:test()和exec()都是正則放在前面。

  • test()方法返回一個布爾值,表示當前模式是否能匹配參數字符串:
/cat/.test('cats and dogs') // true
var r = /x/g;
var s = '_x_x';

r.lastIndex;   // 0
r.test(s);     // true

r.lastIndex;   // 2
r.test(s);     // true

r.lastIndex;   // 4
r.test(s);     // false
複製代碼
  • exec()方法,用來返回匹配結果。若是發現匹配,就返回一個數組,成員是匹配成功的子字符串,不然返回null:
var s = '_x_x';
var r1 = /x/;
var r2 = /y/;

r1.exec(s);   // ["x"]
r2.exec(s);   // null
複製代碼

13.字符串的實例方法:match()、search()、replace()、split(),正則放在後面。

  • match(): 返回一個數組,成員是全部匹配的子字符串。
var s = '_x_x';
var r1 = /x/;
var r2 = /y/;

s.match(r1);   // ["x"]
s.match(r2);   // null

// 設置正則表達式的lastIndex屬性,對match方法無效,匹配老是從字符串的第一個字符開始:
var r = /a|b/g;
r.lastIndex = 7;
'xaxb'.match(r);   // ['a', 'b']
r.lastIndex;       // 0
複製代碼
  • search():按照給定的正則表達式進行搜索,返回一個整數,表示匹配開始的位置。
'_x_x'.search(/x/);   // 1
複製代碼
  • replace():按照給定的正則表達式進行替換,返回替換後的字符串。
'aaa'.replace('a', 'b');   // "baa"
'aaa'.replace(/a/, 'b');   // "baa"
'aaa'.replace(/a/g, 'b');  // "bbb" 添加修飾符g纔會進行總體替換,不然只替換第一個匹配
'JavaScript'.replace(/([A-Z])/g, '_$&')   // "_Java_Script" ‘$&’表示所匹配到的文本,因此第一個就至關於匹配到J後,用_J來替換
let email = 'Betterman@163.com';
let username = email.replace(/(.*)@.*/, '$1');   // 'Betterman' 截取某段名稱

// 回調函數返回所要替換的內容:
let re = /(.*)@(.*)\.(.*)/,  glob;
let callback = function() {
     glob = arguments;
     return arguments[1] + ' at ' + arguments[2] + ' dot ' + arguments[3];
};

let res = 'Betterman@shenzhen.com'.replace(re, callback); 
console.log(res);    // Betterman at shenzhen dot com
console.log(glob);  // ["Betterman@shenzhen.com", "Betterman", "shenzhen", "com", 0, "Betterman@shenzhen.com"]
// 正則表達式所匹配到的內容 第一組 第二組 第三組 匹配內容所在位置 所進行匹配的字符串(原字符串)
複製代碼
  • split():按照給定規則進行字符串分割,返回一個數組,包含分割後的各個成員。
// 非正則分隔:
'a, b,c, d'.split(',');     // [ 'a', ' b', 'c', ' d' ] 注意有空格

// 正則分隔,去除多餘的空格:
'a, b,c, d'.split(/, */);   // [ 'a', 'b', 'c', 'd' ]

// 指定返回數組的最大成員數:
'a, b,c, d'.split(/, */, 2);  // [ 'a', 'b' ]

// 或者:
let space = 'one, two,three ,four';
space.split(',');         // ["one", " two", "three ", "four"] 有空格存在
space.split(/\s*,\s*/);   // ["one", "two", "three", "four"] 無空格
複製代碼

14.處理文章段落,給行首和行尾用正則raplace(/^/gn,'<p>').replace(/$/gn,'</p>')來加上p標籤。

5、面向對象

1.面向對象:將真實世界各類複雜的關係,抽象爲一個個對象,而後由對象之間的分工與合做,完成對真實世界的模擬。

2.面向對象具備封裝性、繼承性、多態性。把同類或者功能整理封裝歸類,須要什麼就去找什麼,就至關於把功能封裝進對象,咱們只是把功能拿來用就行,而不須要了解其實現的原理,對象也不須要知道咱們用這個功能來作什麼。

5.1 this

1.this永遠指向最後調用它的那個對象(使用箭頭函數除外)。

2.this判斷:優先級

  • ①是不是new綁定;
  • ②是不是顯式(硬)綁定,如call、apply、bind;(傳入null或undefined時就是想忽略this,會啓用默認綁定window,因此最好建立一個空對象來替代,如Object.create(null),這個比{}更空);
  • ③是不是隱式綁定,對象調用這個函數;
  • ④默認綁定,window。

3.this綁定:

  • call:參數應該是一個對象,若是參數爲空、null和undefined,則默認傳入全局對象,第一個參數就是this所要指向的那個對象,後面的參數則是函數調用時所需的參數:
function add(a, b) {
    return a + b;
}
add.call(this, 1, 2);   // 3
複製代碼
  • apply:與call同樣,只是參數爲數組而已:
// 找出數組最大元素
Math.max.apply(null, [10, 2, 4, 15, 9]);   // 15
複製代碼
  • bind:返回一個新函數,而不是像call、apply直接執行返回值。

5.2 原型與繼承

1.可參考我以前寫的一篇博客:完全弄懂JS原型與繼承

2.建立實例前與建立實例後修改構造函數原型的區別:

  • ①若是在已經生成實例的狀況下再給構造函數新建立一個原型,則會切斷了構造函數與最初原型的聯繫,即新原型覆蓋了舊原型。但此時實例上的原型依舊指向最初的原型,而不是指向新構建的原型:
function Person () {}
let person1 = new Person();
Person.prototype = {
    constructor: Person,
    name: 'BetterMan',
    age: 26,
    sayName: function(){
        console.log(this.name);
    }
}
person1.sayName();   // 報錯,實例依舊指向舊原型
複製代碼
  • ②若是在建立實例前重寫構造函數的原型,實例的原型是指向重寫後的原型:
function Person () {}
Person.prototype = {
    constructor: Person,
    name: 'BetterMan',
    age: 26,
    sayName: function(){
        console.log(this.name);
    }
}
let person1 = new Person(); 
person1.sayName();    // "BetterMan"
複製代碼

3.__proto__

  • 實例.__proto__ === 構造函數.prototype // true
  • __proto__雖然能夠獲得實例的原型,但__proto__prototype不是等價的
  • __proto__其實是實例對象的屬性,而prototype是屬於構造器函數的屬性

4.__proto__與其說是屬性,實際更像是getter/setter,像一個函數,訪問a.__proto__時,其實是調用a.__proto__()__ptoto__是繼承自Object.prototype

Object.definedProperty(Object.prototype, '__proto__', {
   		get: function() {
                return Object.getPrototypeOf(this);
           },
        set: function(o) {
                return Object.setPrototypeOf(this, o);
          }
})
複製代碼
  1. 原型
Object instanceof Object // true Object.__proto__===Function.prototype Function.prototype.__proto__===Object.prototype
Function instanceof Function // true Function.__proto__===Function.prototype
Function instanceof Object // true Function.__proto__===Function.prototype Function.prototype.__proto__===Object.prototype
複製代碼

6.幾種特殊的原型:

  • ①空對象的原型是 Object.prototype:
Object.getPrototypeOf({}) === Object.prototype   // true
複製代碼
  • ②Object.prototype 的原型是 null:
Object.getPrototypeOf(Object.prototype) === null   // true
複製代碼
  • ③函數的原型是 Function.prototype:
function f() {}
Object.getPrototypeOf(f) === Function.prototype   // true
複製代碼

7.Object.create()方法的基本原理:

function create(o) {  
    function F() {};
    F.prototype = o;
    return new F();
}
複製代碼

5.3 類

1.類就像設計師設計出的藍圖,實例就像根據藍圖所建造出來的建築。

2.js的類不像標準的類是複製一個副本,它相似於共享。

3.標準的繼承應該是類與類之間的關係,而js的繼承時「類」與實例之間的關係,或者應該說是對象與對象之間的關係。

4.繼承的本來意思應該是複製,而js默認是不會複製對象屬性的,相反,js會在兩個對象之間建立一個關聯,這樣一個對象就能夠經過委託訪問另外一個對象的屬性和函數,進而找到所須要的屬性,委託行爲意味着某些對象在找不到屬性或方法時,會把這個請求委託給另外一個對象,這並非像父類到子類的關係垂直組織的,而是經過任意方向的委託關係並排組織的。

  • ①將B.prototype關聯到A.prototype的方法:
//ES6前:
B.prototype = new A();

//ES6:
Object.setPrototypeOf(B.prototype, A.prototype);
複製代碼
  • ②判斷某個對象的原型鏈上是否存在某對象:
//方式一:
F.prototype.isPrototypeOf(a);

//方式二:
Object.getPrototypeOf(a) === F.prototype;
複製代碼

5.4 事件流

  1. DOM2事件流包含事件捕獲、處於目標、事件冒泡三個階段,addEventListener('事件名', '回調', '布爾值'),第三個參數爲true時指在事件捕獲階段執行事件,爲false時爲在冒泡階段執行,默認爲false,IE只支持冒泡。

  2. 若是在同一個節點上同時設置了捕獲事件和冒泡事件,若是該節點是目標節點,無論第三參數爲什麼,都會按照事件的書寫順序來執行(若是不是目標節點,則會按照先捕獲後冒泡執行):

<div class="a1">
    <div class="a2">
        <div class="a3">a3</div>
    </div>
</div>

var a1 = document.getElementsByClassName('a1')
var a2 = document.getElementsByClassName('a2')
var a3 = document.getElementsByClassName('a3')
        
a1[0].addEventListener('click', function (event) {
    console.log('a1')
}, false)  
a2[0].addEventListener('click', function (event) {
    console.log('a2') 
}, false)
a2[0].addEventListener('click', function (event) {
    console.log('a22')
}, true)
a3[0].addEventListener('click', function (event) {
    console.log('a33')
}, false)  // 雖然爲false, 但寫在前會先執行
a3[0].addEventListener('click', function (event) {
    console.log('a3')
}, true)

// 點擊a3時:a22 a33 a3 a2 a1
複製代碼

最後

由於比較多,因此目前只整理到這裏,後續有些比較重要難懂的模塊會分開更新,同時包括ES6的部分,但願對你有所幫助,若有不合理的地方歡迎指正,喜歡的話歡迎關注一波,後續會持續更新。

GitHub傳送門
博客園傳送門

相關文章
相關標籤/搜索