面向過(guò)程POP
Javascript進(jìn)階
面向過(guò)程POP
? (process-oriented programming)分析出解決問(wèn)題所需的步驟,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn),使用的時(shí)候再一個(gè)一個(gè)的依次調(diào)用就可以了
面向?qū)ο驩OP
(object oriented programming)把事務(wù)分解成一個(gè)個(gè)對(duì)象,然后由對(duì)象之間分工合作。
OOP的特性:封裝性,繼承性,多態(tài)性
對(duì)象是一組無(wú)序的相關(guān)屬性和方法的集合。
【類class】
創(chuàng)建類? class name {
? ? ? ? ? }
創(chuàng)建實(shí)例? var xx = name(); 類必須使用new實(shí)例化對(duì)象
類constructor構(gòu)造函數(shù)
constructor()方法是類的構(gòu)造函數(shù)(默認(rèn)的方法),用于傳遞參數(shù),返回實(shí)例對(duì)象,通過(guò)new命令生成對(duì)象實(shí)例時(shí),自動(dòng)調(diào)用該方法,如果沒(méi)有顯示定義,類內(nèi)部會(huì)自動(dòng)給我們創(chuàng)建一個(gè)constructor()
語(yǔ)法:
class Person {
? ? constructor (name,age) {? //構(gòu)造方法或構(gòu)造函數(shù)
? ? ? ? ? this.name = name;
? ? ? ? ? this.age = age;
? ? }
? ? say () {
? ? }
}
var ldh = new Person('劉德華',18);
繼承extends
class Father {
}
class Son extends Father {
}
【super】關(guān)鍵字-訪問(wèn)和調(diào)用對(duì)象父類上的函數(shù)
class Person {
? ? constructor (surname) {
? ? ? this.surname = surname;
? }
}
class Student extends Person { //子類繼承父類
? ? constructor (surname,firstname) {
? ? ? super(surname);? // 調(diào)用父類的constructor(surname)
? ? ? ? this.firstname = firstname;//定義子類獨(dú)有的屬性
? ? }
}
注意:super必須放到this前面?
super用于訪問(wèn)和調(diào)用對(duì)象父類上的函數(shù),可以調(diào)用父類的構(gòu)造函數(shù),也可以調(diào)用父類的普通函數(shù)
在ES6中類沒(méi)有變量提升,所以必須先定義類,才能通過(guò)類實(shí)例化對(duì)象。
類里面的共有屬性和方法一定要加this使用。
類里面的this指向問(wèn)題。
constructor 里面的this指向?qū)嵗龑?duì)象,方法里面的this指向這個(gè)方法的調(diào)用者。
insertAdjacentHTML(追加的位置,'要追加的字符串元素')-可以直接把字符串格式的元素添加到父元素中。不可以用appendChild追加。
追加的位置-beforeend插入元素內(nèi)部的最后一個(gè)子節(jié)點(diǎn)之后。
禁止選中文字
window.getSelection?window.getSelection().removeAllRanges() : document.selection.empty();
構(gòu)造函數(shù)-一種特殊的函數(shù),主要用來(lái)初始化對(duì)象,即為對(duì)象成員變量賦初始值,它總與new一起使用,我們可以把對(duì)象中一些公共的屬性和方法抽取出來(lái),然后封裝到這個(gè)函數(shù)里面。
在Js中使用構(gòu)造函數(shù)時(shí)需要注意以下兩點(diǎn)∶
構(gòu)造函數(shù)用于創(chuàng)建某一類對(duì)象,其首字母要大寫。構(gòu)造函數(shù)要和new一起使用才有意義。
new在執(zhí)行時(shí)會(huì)做四件事:
在內(nèi)存中創(chuàng)建一個(gè)新的空對(duì)象。
讓this指向這個(gè)新的對(duì)象。
執(zhí)行構(gòu)造函數(shù)里面的代碼,給這個(gè)新對(duì)象添加屬性方法。
返回這個(gè)新對(duì)象(所以構(gòu)造函數(shù)里面不需要return)
構(gòu)造函數(shù)可以添加一些成員,可以在構(gòu)造函數(shù)本身上添加,也可以在構(gòu)造函數(shù)內(nèi)部的this上添加。通過(guò)這兩種方法添加的成員分別稱為靜態(tài)成員和實(shí)例成員。
靜態(tài)成員:在構(gòu)造函數(shù)本身上添加的成員,只能由構(gòu)造函數(shù)本身來(lái)訪問(wèn)。
實(shí)例成員:在構(gòu)造函數(shù)內(nèi)部創(chuàng)建的對(duì)象成員,只能由實(shí)例化的對(duì)象來(lái)訪問(wèn)。
構(gòu)造函數(shù)原型prototype
構(gòu)造函數(shù)通過(guò)原型分配的函數(shù)是所有對(duì)象所共享的,js規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype 屬性,指向另一個(gè)對(duì)象。注意這個(gè)prototype就是一個(gè)對(duì)象,這個(gè)對(duì)象的所有方法和屬性,都會(huì)被構(gòu)造函數(shù)所擁有。我們可以把那些不變的方法直接定義在prototype對(duì)象上,這樣所有對(duì)象的實(shí)例就可以共享這些方法。
原型是什么-一個(gè)對(duì)象,我們也稱為prototype為原型對(duì)象。作用是共享方法。
function Star (uname,age) {
? ? this.uname = unane;
? ? this.age = age;
}
Star.prototype.sing = function (){
}//在原型上添加共有方法
對(duì)象原型__proto__
對(duì)象都會(huì)有一個(gè)屬性__proto__指向構(gòu)造函數(shù)的prototype 原型對(duì)象,之所以我們對(duì)象可以使用構(gòu)造函數(shù)函數(shù)prototype原型對(duì)象的方法,就因?yàn)閷?duì)象有__proto__原型存在。
__proto__對(duì)象原型和原型對(duì)象prototype是等價(jià)的,
__proto__對(duì)象原型的意義就在于為對(duì)象的查找機(jī)制提供一個(gè)方向,或者說(shuō)一條線,但是它是一個(gè)非標(biāo)準(zhǔn)屬性,因此實(shí)例開(kāi)發(fā)中,不可以使用這個(gè)屬性,它只是內(nèi)部指向原型對(duì)象prototype.
三者之間關(guān)系
Star構(gòu)造函數(shù)通過(guò)Star.prototype指向Star原型對(duì)象prototype
Star原型對(duì)象prototype通過(guò)原型對(duì)象.constructor指向Star構(gòu)造函數(shù)
Star構(gòu)造函數(shù)直接指向它的ldh實(shí)例化對(duì)象
ldh對(duì)象實(shí)例通過(guò)ldh.__proto__指向Star原型對(duì)象prototype
__proto__和prototype里面都有一個(gè)constructor 屬性,constructor我們稱為構(gòu)造函數(shù),因?yàn)樗赶驑?gòu)造函數(shù)本身。
constructor主要用于記錄該對(duì)象引用于哪個(gè)構(gòu)造函數(shù),它可以讓原型對(duì)象重新指向原來(lái)的構(gòu)造函數(shù)。
JS查找機(jī)制
先查找自身屬性-再查找原型-查找對(duì)象的原型Object 的原型-null
__proto__的意義就在于為對(duì)象成員查找提供一個(gè)方向,或者說(shuō)一條路線。
原型對(duì)象this指向
構(gòu)造函數(shù)里的this指向?qū)嵗龑?duì)象。
原型對(duì)象里面放的是方法,這個(gè)方法里面的this指向的是這個(gè)方法的調(diào)用者,也就是這個(gè)實(shí)例對(duì)象。
通過(guò)原型對(duì)象,對(duì)原來(lái)的內(nèi)置對(duì)象進(jìn)行擴(kuò)展自定義的方法。
繼承【繼承】
ES6之前沒(méi)有給我們提供extends繼承,我們可以通過(guò)構(gòu)造函數(shù)+原型對(duì)象模擬實(shí)現(xiàn)繼承,也就是組合繼承。
call()方法
fun.call(thisArg,arg1,arg2...)
thisArg:當(dāng)前調(diào)用函數(shù)this的指向?qū)ο?/p>
arg1:傳遞的其他參數(shù)
借用構(gòu)造函數(shù)繼承父類型屬性
核心原理:通過(guò)call()把父類型的this指向子類型的this,這樣就可以實(shí)現(xiàn)子類型的屬性。
function Father (name,age) {
? ? this.name=name;
? ? this.age=age;
}
function Son (name,age,sex) {
? ? Father.call(this,name,age);//父類的this指向子類的this,.同時(shí)調(diào)用這個(gè)函數(shù)
? ? this.sex=sex;
}
var xt= new Son('ez','18','男');
借用原型對(duì)象繼承父類型方法
一般情況下,對(duì)象的方法都在構(gòu)造函數(shù)的原型對(duì)象中設(shè)置,通過(guò)構(gòu)造函數(shù)無(wú)法繼承父類方法。核心原理-
將子類所共享的方法提取出來(lái),讓子類的prototype原型對(duì)象=new 父類(),
本質(zhì)-子類原型對(duì)象等于是實(shí)例化父類,因?yàn)楦割悓?shí)例化之后另外開(kāi)辟空間,就不會(huì)影響原來(lái)父類原型對(duì)象,將子類的constructor 重新指向子類的構(gòu)造函數(shù)。
類的本質(zhì)
class的本質(zhì)還是function
類的所有方法都定義在類的prototype屬性上
類創(chuàng)建的實(shí)例,里面也有__proto__指向類的prototype原型對(duì)象
ES6的類它的絕大部分功能,Es5都可以做到,新的class寫法只是讓對(duì)象原型的寫法更加清晰,更像面向?qū)ο缶幊痰恼Z(yǔ)法而已
ES5新增的方法
數(shù)組方法
foreach()
array.foreach(function(currentValue,index,arr){})
currentValue:數(shù)組當(dāng)前項(xiàng)的值
index:數(shù)組當(dāng)前項(xiàng)的索引號(hào)
arr:數(shù)組對(duì)象本身
arr.foreach(function(value,index,array){
//函數(shù)內(nèi)部可以獲取到參數(shù)值
? ? })
filter()篩選元素,返回新數(shù)組
array.filter(function(value,index,array){
//函數(shù)內(nèi)部可以獲取到參數(shù)值
? ? })
currentValue:數(shù)組當(dāng)前項(xiàng)的值
index:數(shù)組當(dāng)前項(xiàng)的索引號(hào)
arr:數(shù)組對(duì)象本身
返回一個(gè)新數(shù)組,新數(shù)組中的元素是通過(guò)檢查指定數(shù)組中符合條件的所有元素,主要用于篩選數(shù)組。
例子-
var arr=[12,66,4,88,3,7];
var newArr=arr.filter(function(value,index){
? return value%2===0;
});
some()查找元素,返回布爾值
array.some(function(value,index,array){
//函數(shù)內(nèi)部可以獲取到參數(shù)值
? ? })
currentValue:數(shù)組當(dāng)前項(xiàng)的值
index:數(shù)組當(dāng)前項(xiàng)的索引號(hào)
arr:數(shù)組對(duì)象本身
用于檢測(cè)數(shù)組中的元素是否滿足指定條件,查找數(shù)組中是否滿足條件的元素。
返回布爾值,如果查到這個(gè)元素就返回true,查不到返回false.
找到你一個(gè)滿足條件的元素,則終止循環(huán),不再繼續(xù)查找。
把數(shù)據(jù)渲染到頁(yè)面-foreach
根據(jù)價(jià)格顯示數(shù)據(jù)-filter
字符串方法
str.trim(),刪除字符串兩端的空白字符,不影響原字符串本身,返回新字符串,可用于用戶輸入空格失去焦點(diǎn)時(shí)清空表單。
對(duì)象方法
Object.keys(obj)用于獲取對(duì)象自身所有屬性
類似for...in
返回一個(gè)由屬性名組成的數(shù)組。
Object.defineProperty(obj,prop,descriptor)
obj-必需,目標(biāo)對(duì)象
prop-必需,需定義或修改的屬性的名字
descriptor-必需,目標(biāo)屬性所擁有的特性,以對(duì)象{}形式書寫,value:設(shè)置屬性的值,默認(rèn)undefined
writable:值是否可以重寫,true|false,默認(rèn)為false
enumerable:目標(biāo)屬性是否可以被枚舉,true|false,默認(rèn)為false
configurable:目標(biāo)屬性是否可以被刪除或是否可以再次修改特性true|false,默認(rèn)為false
定義對(duì)象中新屬性或者修改原有屬性。
改變函數(shù)內(nèi)部this指向
1.call方法
call()方法調(diào)用一個(gè)對(duì)象,簡(jiǎn)單理解為調(diào)用函數(shù)的方式,但是它可以改變函數(shù)的this指向。
fun.call(thisArg,arg1,arg2...)
thisArg:在fun函數(shù)運(yùn)行時(shí)指定的this值
arg:傳遞的其他參數(shù)
返回值就是函數(shù)的返回值,因?yàn)樗褪钦{(diào)用函數(shù)。
因此當(dāng)我們想改變this指向,同時(shí)想調(diào)用這個(gè)函數(shù),可以使用call,比如繼承
2.apply方法
fun.apply(thisArg,[argArray])
thisArg:在fun函數(shù)運(yùn)行時(shí)指定的this值
argArray:傳遞的值,必須包含在數(shù)組里面
返回值就是函數(shù)的返回值,因?yàn)樗褪钦{(diào)用函數(shù)
因此apply主要和數(shù)組有關(guān),比如使用Math.max()求數(shù)組的最大值
var arr=[1,66,3,99,4];
var max=Math.max.apply(Math,arr);
3.bind方法
fun.bind(thisArg,arg1,arg2...)
thisArg:在fun函數(shù)運(yùn)行時(shí)指定的this值
arg:傳遞的其他參數(shù)
返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝
因此當(dāng)我們只是想改變this指向,并且不想調(diào)用這個(gè)函數(shù)的時(shí)候可以使用bind
call,apply,bind總結(jié)
相同點(diǎn):改變函數(shù)內(nèi)部this指向
區(qū)別:call和apply會(huì)調(diào)用函數(shù),且改變函數(shù)內(nèi)部this指向,
call和apply傳遞參數(shù)不一樣,后者是數(shù)組形式,bind不會(huì)調(diào)用函數(shù)
應(yīng)用場(chǎng)景:call-繼承
aplly-與數(shù)組有關(guān),求最大值最小值
bind-改變定時(shí)器內(nèi)部this指向
嚴(yán)格模式
'use strict'
1.為腳本開(kāi)啟嚴(yán)格模式
(function () {
? 'use strict';
})();
2.為函數(shù)開(kāi)啟嚴(yán)格模式
嚴(yán)格模式中的變化
1.變量規(guī)定-在正常模式下,一個(gè)變量不聲明就賦值,默認(rèn)是全局變量,嚴(yán)格模式下禁止這種用法,變量必須才用var命令聲明,然后再使用。
嚴(yán)禁刪除已經(jīng)聲明的變量。例如delete x;語(yǔ)法是錯(cuò)誤的。
2.嚴(yán)格模式下this指向問(wèn)題
以往全局作用域函數(shù)中的this指向window對(duì)象。嚴(yán)格模式下全局作用域函數(shù)中的this是undefined。以前構(gòu)造函數(shù)時(shí)不加new也可以調(diào)用,當(dāng)普通函數(shù),this指向全局對(duì)象。嚴(yán)格模式下,如果構(gòu)造函數(shù)不加new調(diào)用,this指向的是undefined,如果給他賦值則會(huì)報(bào)錯(cuò)。
new實(shí)例化的構(gòu)造函數(shù)指向創(chuàng)建的對(duì)象實(shí)例。
定時(shí)器this還是指向window。事件、對(duì)象還是指向調(diào)用者。
3.函數(shù)變化
函數(shù)不能有重名參數(shù)。
函數(shù)必須聲明在頂層,新版本js會(huì)引入塊級(jí)作用域,為了與新版本接軌,不允許在非函數(shù)的代碼塊內(nèi)聲明函數(shù)。
高階函數(shù):是對(duì)其他函數(shù)進(jìn)行操作的函數(shù),它接收函數(shù)作為參數(shù)或?qū)⒑瘮?shù)作為返回值輸出。
閉包:有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù)。就是一個(gè)作用域可以訪問(wèn)另一個(gè)函數(shù)內(nèi)部的局部變量。
閉包的作用-延伸變量的作用范圍。
閉包案例:打車價(jià)格
遞歸,一個(gè)函數(shù)在內(nèi)部調(diào)用其本身,那個(gè)這個(gè)函數(shù)就是遞歸函數(shù)。遞歸函數(shù)的作用和循環(huán)效果一樣。遞歸容易發(fā)生棧溢出,所以必須要加return退出條件。
遞歸案例:
求1-n的階乘
求斐波那契數(shù)列
function fb(n) {
? if( n===1 || n=== 2){
? ? ? return 1;
}
return fb(n-1)+fb(n-2);
}
根據(jù)id返回對(duì)應(yīng)的數(shù)據(jù)對(duì)象。
淺拷貝只拷貝一層,更深層次對(duì)象級(jí)別的只拷貝引用。
深拷貝拷貝多層,每一級(jí)別的數(shù)據(jù)都會(huì)拷貝。
Object.assign(target,...sources) es6新增方法可以淺拷貝
深拷貝封裝
function deepCopy(newobj,oldobj) {
? ? for(var k in oldobj){
? ? ? ? var item = oldobj[k];
? ? ? ? if (item instanceof Array) {
? ? ? ? ? ? newobj[k] = [];
? ? ? ? ? ? deepCopy(newobj[k],item);
? ? ? ? } else if (item instanceof Object){
? ? ? ? ? ? newobj[k] = {};
? ? ? ? ? ? deepCopy(newobj[k],item);
? ? ? ? } else {
? ? ? ? ? ? newobj[k] = item;
? ? ? ? }
? ? }
}