1.面向過程與面向對象
2.對象與類
this.uname = name;
3.構造函數和原型
3.1 靜態成員和實例成員
實例成員 :實例成員就是構造函數內部通過this添加的成員,實例成員只能通過實例化的對象來訪問
以下代碼里的 uname age sing就是實例成員
function Star(uname, age) { this.uname = uname; this.age = age; this.sing = function() { console.log('我會唱歌'); } } var ldh = new Star('劉德華', 18); console.log(ldh.uname); //實例成員只能通過實例化的對象來訪問
靜態成員 :在構造函數本身上添加的成員 靜態成員只能通過構造函數來訪問 在ES5中只要被static修飾的屬性和方法都是靜態成員
下列代碼中 sex 就是靜態成員
function Star(uname, age) { this.uname = uname; this.age = age; this.sing = function() { console.log('我會唱歌'); } } Star.sex = '男'; var ldh = new Star('劉德華', 18); console.log(Star.sex); //靜態成員只能通過構造函數來訪問
3.2構造函數的問題
存在浪費內存的問題
function Star(uname , age) { this.uname = uname; this.age = age; this.sing = function(){ console.log('我會唱歌') } } var ldh = new Star("劉德華",18); var shuji= new Star("書記",22); ldh.sing(); shuji.sing();
以上代碼在調用sing方法時都會在內存開辟一個新的空間,如果有多個對象來調用sing方法就會占用過多內存,所以我們就用到了構造函數的原型 prototype。
3.3 構造函數原型prototype
構造函數通過原型分配的函數是所有對象所共享的。
JavaScript 規定,每一個構造函數都有一個prototype 屬性,指向另一個對象。注意這個prototype就是一個對象,這個對象的所有屬性和方法,都會被構造函數所擁有。
我們可以把那些不變的方法,直接定義在 prototype 對象上,這樣所有對象的實例就可以共享這些方法。
構造函數.prototype就可以獲取原型對象
function Star(uname, age) { this.uname = uname; this.age = age; } Star.prototype.sing = function() { console.log('我會唱歌'); } var ldh = new Star('劉德華', 18); var zxy = new Star('張學友', 19); ldh.sing(); //我會唱歌 zxy.sing(); //我會唱歌
3.4 對象原型
實例化對象都會有一個__proto__屬性指向構造函數的原型對象,而我們的實例化對象可以使用對象原型的屬性和方法就是因為有__proto__屬性的存在
實例化對象.__proto__ === 構造函數.prototype
它們的三角關系如下圖:
__proto__對象原型的意義就在於為對象的查找機制提供一個方向,或者說一條路線,但是它是一個非標准屬性,因此實際開發中,不可以使用這個屬性,它只是內部指向原型對象prototype
3.5 constructor構造函數
對象原型( __proto__)和構造函數(prototype)原型對象里面都有一個屬性constructor 屬性
constructor 我們稱為構造函數,因為它指回構造函數本身。
constructor 主要用於記錄該對象引用於哪個構造函數,它可以讓原型對象重新指向原來的構造函數。
3.6 原型鏈和查找機制
每一個實例對象又有一個proto屬性,指向的構造函數的原型對象,構造函數的原型對象也是一個對象,也有proto屬性,這樣一層一層往上找就形成了原型鏈。
查找機制:
當訪問一個對象的屬性(包括方法)時,首先查找這個對象自身有沒有該屬性,如果自身有,就有自身的屬性和方法。
如果沒有就查找它的原型(也就是 __proto__指向的 prototype 原型對象)。
如果還沒有就查找原型對象的原型(Object的原型對象)。依此類推一直找到 Object 為止(null)。
如果找到盡頭(null)都沒找到,是屬性則返回undefined,是方法則報錯
3.7 原型對象中this的指向
構造函數中的this和原型對象的this,都指向我們new出來的實例對象
3.8 通過原型對象為數組擴展內置方法
var arr = [3,6,9,8,5] arr.prototype.sum = function() { var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return sum; }; //此時數組對象中已經存在sum()方法了 可以用於數組.sum()進行數據的求和
4.繼承
4.1 call()
call()可以調用函數 可以修改this的指向,使用call()的時候,()里的第一個參數是修改的this指向,參數2 參數3 使用逗號隔開
function fn(x, y) { console.log(this); console.log(x + y); } var o = { name: 'andy' }; fn.call(o, 1, 2); //調用了函數此時的this指向了對象o,
4.2 構造函數繼承屬性
// 1. 父構造函數 function Father(uname, age) { // this 指向父構造函數的對象實例 this.uname = uname; this.age = age; } // 2 .子構造函數 function Son(uname, age, score) { // this 指向子構造函數的對象實例 //3.使用call方式實現子繼承父的屬性 Father.call(this, uname, age); this.score = score; } var son = new Son('劉德華', 18, 100); console.log(son);
4.3 借用原型對象繼承方法
// 1. 父構造函數 function Father(uname, age) { // this 指向父構造函數的對象實例 this.uname = uname; this.age = age; } Father.prototype.money = function() { console.log(100000); };
// Son.prototype = Father.prototype; 這樣直接賦值會有問題,如果修改了子原型對 象,父原型對象也會跟着一起變化 Son.prototype = new Father(); // 如果利用對象的形式修改了原型對象,別忘了利用constructor 指回原來的構造函數 Son.prototype.constructor = Son; // 這個是子構造函數專門的方法 Son.prototype.exam = function() { console.log('孩子要考試'); } var son = new Son('劉德華', 18, 100); console.log(son);
5.ES5新增方法
5.1 forEach()遍歷數組 沒有返回值
array.forEach(function(value , index , array){....})
value是每個數組元素
index是每個元素索引值
array是當前數組
5.2 filter()篩選數組 其實也會遍歷數組
array.filter(function(value , index , array){
return 條件表達式
})
返回的是一個新數組 括號跟的參數都是一樣的
5.3 some() 查找數組中是否有滿足條件的元素 其實也會遍歷數組
array.some(function(value , index , array){
return 條件表達式
})
返回值是布爾值,只要查找到第一個滿足條件的元素就會終止循環 效率高
5.4 trim方法去除字符串兩端的空格
字符串的特性 不可變性
var str = ' hello ' ; console.log(str.trim()) //hello 去除兩端空格 var str1 = ' he l l o ' ; console.log(str1.trim()) //he l l o 去除兩端空格
5.5 獲取對象的屬性名
Object.keys(對象) 獲取到當前對象中的屬性名 ,返回值是一個數組
var obj = { id: 1, pname: '小米', price: 1999, num: 2000 }; var result = Object.keys(obj); console.log(result) //返回的新數組[id,pname,price,num]
5.6 Object.defineProperty設置或修改對象中的屬性
Object.defineProperty(對象,修改或新增的屬性名,{ value:修改或新增的屬性的值, writable:true/false, //如果值為false 不允許修改這個屬性值 enumerable: false, //enumerable 如果值為false 則不允許遍歷 configurable: false //configurable 如果為false 則不允許刪除這個屬性 屬性是否可以被刪除或是否可以再次修改特性 })
6.函數的定義和調用
6.1 函數的定義方式
(1) function關鍵字(命名函數)
function fn(){......}
(2) 函數表達式(匿名函數)
var fn = function(){......}
(3) 利用new function('參數1','參數2','函數體')
var f = new Function('a','b','console.log(a +b)'); //參數都必須是字符串格式
f( 3, 2); //輸出結果是5
所有函數都是Function的實例,函數也屬於對象
6.2 函數的調用方式
1 // 1.普通函數 2 function fn(){ 3 console.log('hello world') 4 } 5 fn(); 6 7 // 2.對象的方法 8 var o = { 9 sayHi : function(){ 10 console.log('hello world') 11 } 12 } 13 o.sayHi(); 14 15 // 3.構造函數 16 function Star(){}; 17 new Star(); 18 19 20 // 4.綁定函數事件 21 btn.onclick = function(){} // 點擊了按鈕就可以調用這個函數 22 23 // 5.定時器函數 24 setInterval(function(){},1000); // 這個函數定時器自動一秒鍾調用一次 25 26 //6.立即執行函數(自調用函數) 27 (function(){ 28 console.log('hello world') 29 })();
7.this
7.1 函數內部的this指向
一般情況下,this指向函數的調用者
7.2 改變函數內部this的指向
1.call()方法
可以直接調用函數,也可以改變this的指向
應用:經常做繼承
2.apply()方法
可以直接調用函數,也可以改變this的指向
應用:跟數組有關
// 利用apply借助數學內置對象求最大值等
var arr = [1,56,55,4,33]; var max = Math.max.apply(Math,arr); console.log(max) // 輸出結果應該是56
3. bind()方法
不會調用函數,但是可以改邊this的指向,返回的是一個新函數
應用:不調用函數,但是還想改變this指向
4. call、apply、bind三者區別
call和apply都是直接調用函數,可以改變this的指向
call后面跟的參數是列表形式,apply跟的是數組形式
bind不會直接調用函數,也可以改變ths的指向
8. 嚴格模式(strict mode)
ES5 的嚴格模式是采用具有限制性 JavaScript變體的一種方式,即在嚴格的條件下運行 JS 代碼。
8.1 為腳本開啟嚴格模式
(function (){ //在當前的這個自調用函數中有開啟嚴格模式,當前函數之外還是普通模式 "use strict"; var num = 10; function fn() { } })(); //或者 <script> "use strict"; //當前script標簽開啟了嚴格模式 </script> <script> //當前script標簽未開啟嚴格模式 </script>
8.2 為函數開啟嚴格模式
要給某個函數開啟嚴格模式,需要把“use strict”; (或 'use strict'; ) 聲明放在函數體所有語句之前。
function fn(){ "use strict"; return "123"; } //當前fn函數開啟了嚴格模式
8.3 嚴格模式中的變化
'use strict'; num = 10 ; console.log(num)//嚴格模式后使用未聲明的變量 ‐‐‐ ‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ var num2 = 1; delete num2;//嚴格模式不允許刪除變量 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐ function fn() { console.log(this); // 嚴格模式下全局作用域中函數中的 this 是 undefined } fn(); ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐‐ function Star() { this.sex = '男'; } // Star();嚴格模式下,如果 構造函數不加new調用, this 指向的是undefined 如果給 他賦值則 會報錯. var ldh = new Star(); console.log(ldh.sex); ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐‐‐ setTimeout(function() { console.log(this); //嚴格模式下,定時器 this 還是指向 window }, 2000);
9.高階函數
高階函數是對其他函數進行操作的函數,可以接收函數作為參數或者將函數作為返回值輸出。
函數也是一種數據類型,同樣可以作為參數,傳遞給另外一個參數使用。最典型的就是作為回調函數。同理函數也可以作為返回值傳遞回來
10.閉包(clsure)
閉包是指有權訪問另一個函數作用域中變量的函數。簡單理解就是一個作用域可以訪問另外一個函數內部的局部變量。
作用: 延伸變量的作用范圍,增長了變量的生命周期。
弊端: 造成內存泄漏。(內存泄漏,就是本該銷毀的數據沒有銷毀,造成內存浪費)
閉包里的經典面試題:
1. 遍歷注冊li的點擊事件,利用閉包的實行,點擊每一個li輸出對應的索引
for (var i = 0; i < lis.length; i++) { // 利用for循環創建了4個立即執行函數 // 立即執行函數也成為小閉包因為立即執行函數里面的任何一個函數都可以使用它的i這個變量
(function(i) { lis[i].onclick = function() { console.log(i); } })(i);
}
2. 遍歷 1 ~ 5 5個數值,利用閉包,在setTimeout里面輸入 1 ~ 5
for (var i = 0; i < 5; i++) { (function(i) { setTimeout(function() {
console.log(lis[i].innerHTML);
}, 3000)
})(i);
}
11.遞歸
如果一個函數在內部可以調用其本身,那么這個函數就是遞歸函數。
簡單理解:函數內部自己調用自己, 這個函數就是遞歸函數
遞歸函數的作用和循環效果一樣,很容易發生‘棧溢出’錯誤(stack overflow),所以必須要加退出條件return。
1. 利用遞歸求1~n的階乘
function fn(n){ if (n == 1) { return 1; } return n * fn(n -1) } console.log(fn(3))
2. 利用遞歸求斐波那契數列(斐波那契數列就是前兩個數的和等於第三個數字,也叫兔子數)
// 利用遞歸函數求斐波那契數列(兔子序列) 1、1、2、3、5、8、13、21... // 用戶輸入一個數字 n 就可以求出 這個數字對應的兔子序列值 // 我們只需要知道用戶輸入的n 的前面兩項(n‐1 n‐2)就可以計算出n 對應的序列值 function fb(n){ if ( n== 2 || n== 1) { return 1; } return fb( n -1) + fb (n-2); } console.log(fb(3))
12.正則表達式
12.1 什么是正則表達式?
正則表達式(Regular Expression)是用於匹配字符串中字符組合的模式。在JavaScript中,正則表達式也是對象
12.2 作用
1.匹配 2. 替換 3.提取
13.正則表達式在js中的使用
1. 正則表達式的創建
方式一 :通過調用RegExp對象的構造函數創建
var reg = new RegExp(/123/);
console.log(reg); // 輸出結果 /123/
方式二 : 利用字面量創建
var rg = /123/;
2. 測試正則表達式
test()正則對象方法,用於檢測字符串是否符合規則,該方法返回值是布爾類型,true或false,括號里的參數是字符串
var rg = /123/;
console.log(rg.test(123)); // 返回值是true
console.log(rg.test('abc')); // 返回值是false
3. 正則表達式中的特殊字符
3.1邊界符(正則表達式中的邊界符(位置符)用來提示字符所處的位置)
如果 ^和 $ 在一起,表示必須是精確匹配
3.2 字符類
[ ]方括號,表示有一系列字符可供選擇,只要匹配到其中一個就可以了
3.3 量詞符
量詞符用來設定某個模式出現的次數,都是寫在某個模式的后面
逗號前后都不能有空格
3.4 括號總結
大括號{} 量詞符,里面表示重復次數
中括號[] 字符集合,匹配中括號里面的任意字符
小括號() 表示優先級
3.5 預定義類
指的是某些常見模式的簡寫方式
3.6 正則替換和正則提取
replace()方法可以實現替換字符串操作,用來替換的參數可以是一個字符串,也可以是一個正則表達式
注意:replace()是字符串的方法,並不是正則對象的方法
語法: obj.replace(參數1,參數2)
obj是要選擇的目標字符串,參數1是要被替換的字符串,可以是字符串也可以是正則表達式,參數2是替換之后的字符串
var str = "abcd"; // 把字符串里的a替換成 哈哈 var str1 = str.replace("a","哈哈"); var str2 = str.replace(/a/,"哈哈"); console.log(str1); //輸出 哈哈bcd console.log(str2); //輸出 哈哈bcd
match()可以進行提取,返回值是一個數組
語法 : 字符串.match(正則表達式)
str.match(/\w+@\w+\.\w+/g) 可以提取字符串里的所有郵箱
3.7 正則表達式參數
后面可以跟三種形式的參數
/表達式/g 表示全局匹配,就是可以將所有的某個字符都進行轉換
/表達式i/ 忽略大小寫
/表達式/gi 全局匹配+忽略大小寫