前端面向?qū)ο缶幊讨瓻S5語法ES6語法詳解
一.面向?qū)ο缶幊?/h2>
1.概念
- 通過對于具有相同屬性和函數(shù)方法的一類事物的描述,實(shí)現(xiàn)代碼功能
- 對于具有相同屬性和函數(shù)方法的抽象類實(shí)現(xiàn)代碼功能
2.理解
定義一個(gè)對象
利用對象的屬性存儲(chǔ)的數(shù)據(jù)
將程序執(zhí)行需要的數(shù)據(jù)都以屬性的形式,存儲(chǔ)在對象中
利用函數(shù)方法存儲(chǔ)程序代碼
將執(zhí)行程序需要的代碼
以函數(shù)方法的形式存儲(chǔ)
調(diào)用執(zhí)行函數(shù)方法時(shí)
使用的數(shù)據(jù)是對象屬性中存儲(chǔ)的數(shù)據(jù)
二.語法形式
工廠模式
function 函數(shù)(形參,形參...){ const obj= {}; //創(chuàng)建一個(gè)空對象 obj.屬性 = 屬性; obj.屬性 = 屬性; ... 設(shè)定對象的屬性和屬性值 obj.函數(shù)方法 = function(){} obj.函數(shù)方法 = function(){} ... 設(shè)定對象的函數(shù)方法 return obj; 返回值是這個(gè)創(chuàng)建的對象 } /* 工廠模式 是 創(chuàng)建 屬性和函數(shù)方法相同 屬性值不同的 對象 創(chuàng)建的對象 都 相同的屬性 不同的屬性值 還有 完全相同的函數(shù)方法 每一個(gè)對象都存儲(chǔ)了完全相同的函數(shù)方法 造成有 冗余的代碼程序 */
ES5語法
function 構(gòu)造函數(shù)(形參,形參...){ //在構(gòu)造函數(shù)中通過this指向設(shè)定操作對象的屬性 this.屬性 = 形參; this.屬性 = 形參; } //在構(gòu)造函數(shù)外在構(gòu)造函數(shù)的prototype中定義函數(shù) 構(gòu)造函數(shù).prototype.函數(shù)方法 = function(){} 構(gòu)造函數(shù).prototype.函數(shù)方法 = function(){} //通過new關(guān)鍵詞 調(diào)用構(gòu)造函數(shù)創(chuàng)建實(shí)例化對象
ES6語法
使用class關(guān)鍵詞定義構(gòu)造函數(shù) class 構(gòu)造函數(shù){ //在構(gòu)造函數(shù)中定義對象的屬性屬性值 constructor(形參,形參...){ this.屬性 = 形參; this.屬性 = 形參; } //在構(gòu)造函數(shù)外定義函數(shù)方法 js程序自動(dòng)定義在prototype 中 函數(shù)方法(){} 函數(shù)方法(){} } const 實(shí)例化對象 = new 構(gòu)造函數(shù)(實(shí)參,實(shí)參...); 通過new關(guān)鍵詞調(diào)用構(gòu)造函數(shù)創(chuàng)建實(shí)例化對象
三.批量生產(chǎn)對象
字面量方式
const obj = {} obj.a = 1 obj.b = 2 console.log(obj) const obj1 = {} obj1.a = 1 obj1.b = 2 console.log(obj1) //不能批量生產(chǎn)
內(nèi)置構(gòu)造函數(shù)
const obj = new Object() obj.a = 1 obj.b = 2 console.log(obj) const obj1 = new Object() obj1.a = 1 obj1.b = 2 console.log(obj1) //不能批量生產(chǎn)
工廠函數(shù)
function createObj (name, age) { // 1. 手動(dòng)創(chuàng)建一個(gè)對象 const obj = {} // 2. 手動(dòng)向?qū)ο髢?nèi)部添加屬性 obj.name = name obj.age = age // 3. 手動(dòng)返回一個(gè)對象 return obj } //這個(gè)方法能夠創(chuàng)建對象, 并且批量生產(chǎn)也可以
自定義構(gòu)造函數(shù)
function createObj () { // 1. 自動(dòng)創(chuàng)建出來一個(gè)對象 // 2. 手動(dòng)向?qū)ο筇砑訉傩? // 3. 自動(dòng)返回一個(gè)對象 } const o1 = new createObj() // 這種調(diào)用方式, 才是 構(gòu)造函數(shù) const o2 = createObj() // 這就是一個(gè)普通函數(shù)的調(diào)用 console.log(o1) console.log(o2) /* 自定義構(gòu)造函數(shù), 本質(zhì)是就是一個(gè)函數(shù) 當(dāng)他和 new 關(guān)鍵字連用的時(shí)候, 就叫做構(gòu)造函數(shù) 自動(dòng)創(chuàng)建一個(gè)對象 手動(dòng)向創(chuàng)建的對象添加屬性 自動(dòng)返回一個(gè)對象 */
四.自定義構(gòu)造函數(shù)的書寫
1. 一定是和new關(guān)鍵字連用
如果沒有和new連用,那么它就是一個(gè)普通函數(shù)
2.當(dāng)一個(gè)函數(shù)和new關(guān)鍵連用的時(shí)候,這個(gè)函數(shù)就被稱為自定義構(gòu)造函數(shù),這個(gè)函數(shù)內(nèi)容this指向,指向返回出來的對象
3.構(gòu)造函數(shù)不能使用給箭頭函數(shù)
因?yàn)榧^函數(shù)內(nèi)部沒有this
4.構(gòu)造函數(shù)內(nèi)部不需要return
- return了基本數(shù)據(jù)類型,寫了和沒寫一樣
- return 了引用數(shù)據(jù)類型,寫了構(gòu)造函數(shù)就沒用了
5.書寫構(gòu)造函數(shù)時(shí),首字母建議大寫
目的: 僅僅是為了和普通函數(shù)區(qū)分
6.我們構(gòu)造函數(shù)通過new關(guān)鍵字創(chuàng)建出來的對象,叫做實(shí)例化對象,本質(zhì)上還是一個(gè)對象,只不過名字上叫做實(shí)例化對象(實(shí)例對象)
我們把構(gòu)造函數(shù)通過new關(guān)鍵字創(chuàng)建對象的過程叫實(shí)例化
和普通函數(shù)一樣, 只不過 調(diào)用的時(shí)候要和 new 連用 不然就是一個(gè)普通函數(shù)調(diào)用
1.不寫new的時(shí)候就是普通函數(shù)調(diào)用,沒有創(chuàng)造對象的能力
function Person () {} var o1 = new Person() // 一個(gè)對象 var o2 = Person() // 什么也得不到, 就是一個(gè)普通函數(shù)的調(diào)用
2.首字母不大些, 只要和 new 連用, 就有創(chuàng)造對象的能力
function person () {} var o1 = new person() // 一個(gè)對象
3.當(dāng)調(diào)用的時(shí)候, 如果不需要傳遞參數(shù)可以不寫 ()
, 但是建議寫上
function person () {} var o1 = new person // 一個(gè)對象
5.構(gòu)造函數(shù)內(nèi)部的 this, 由于和 new 連用的關(guān)系, 是指向當(dāng)前實(shí)例對象的
function Person () { console.log(this) } var o1 = new Person() // this ---> o1 var o2 = new Person() // this ---> o2
五.使用構(gòu)造函數(shù)創(chuàng)建一個(gè)對象
function Person() { this.name = 'Jack' this.age = 18 } var o1 = new Person() var o2 = new Person()
function Person() { this.name = 'Jack' this.age = 18 this.sayHi = function () { console.log('hello word') } } var o1 = new Person() var o2 = new Person()
// 有缺點(diǎn) function Person() { this.name = 'Jack' this.age = 18 this.sayHi = function () { console.log('hello word') } } /** * 第一次 new 的時(shí)候, Person 這個(gè)函數(shù)要執(zhí)行一遍 * 執(zhí)行一邊就會(huì)創(chuàng)造一個(gè)新的函數(shù), 并且把函數(shù)地址賦值給 this.sayHi */ var o1 = new Person() /** * 第二次 new 的時(shí)候, Person 這個(gè)函數(shù)要執(zhí)行一遍 * 執(zhí)行一遍就會(huì)創(chuàng)造一個(gè)新的函數(shù), 并且把函數(shù)地址賦值給 this.sayHi */ var o2 = new Person()
- 我們在使用構(gòu)造函數(shù)的時(shí)候, 可以通過一些帶啊嗎和內(nèi)容來向當(dāng)前的對象中添加一些內(nèi)容
- 我們得到的兩個(gè)對象里面都有自己的成員 name 和 age
- 我們在寫構(gòu)造函數(shù)的時(shí)候其實(shí)也可以添加一些方法進(jìn)去
這樣也是可以的, 但是有一點(diǎn)小缺點(diǎn)
- 第一次 new 的時(shí)候, Person 這個(gè)函數(shù)要執(zhí)行一遍, 執(zhí)行一遍就會(huì)創(chuàng)造一個(gè)新的函數(shù), 并且把函數(shù)地址賦值給 this.sayHi
- 第二次 new 的時(shí)候, Person 這個(gè)函數(shù)要執(zhí)行一遍, 執(zhí)行一遍就會(huì)創(chuàng)造一個(gè)新的函數(shù), 并且把函數(shù)地址賦值給 this.sayHi
- 這樣寫的話, 我們兩個(gè)對象內(nèi)的
sayHi
函數(shù)就是一個(gè)代碼一模一樣, 功能一模一樣 - 但卻占用了兩個(gè)內(nèi)存空間
- 也就是說
o1.sayHi
是一個(gè)地址,o2.sayHi
是一個(gè)地址 - 所以我們執(zhí)行
console.log(o1.sayHi === o2.sayHi)
的到的結(jié)果是false
- 缺點(diǎn): 一模一樣的函數(shù)出現(xiàn)了兩次, 占用了兩個(gè)空間地址
- 要想解決的話, 就需要一個(gè)東西, 叫做原型
原型
- 原型的出現(xiàn), 就是為了解決 構(gòu)造函數(shù)的缺點(diǎn)
- 也就是給我們提供了一個(gè)給對象添加函數(shù)的方法
- 不然構(gòu)造函數(shù)只能給對象添加屬性, 不能合理的添加函數(shù)就太 low 了
prototype
- 每一個(gè)函數(shù)天生自帶一個(gè)成員, 叫做 prototype, 是一個(gè)對象空間
- 既然每一個(gè)函數(shù)都有, 構(gòu)造函數(shù)也是函數(shù), 構(gòu)造函數(shù)也有這個(gè)對象空間
- 這個(gè)
prototype
對象空間可以由函數(shù)名來訪問
function Person () {} console.log(Person.prototype) // 是一個(gè)對象
- 既然是一個(gè)對象, 那么我們就可以向里面放入一些東西
function Person() {} Person.prototype.name = 'prototype' Person.prototype.sayHi = function () {}
- 重點(diǎn): 在函數(shù)的 prototype 里存儲(chǔ)的內(nèi)容, 不是給函數(shù)使用的, 是給函數(shù)的每一個(gè)實(shí)例化對象使用的
proto
每一個(gè)對象都天生自帶一個(gè)成員, 叫做 __proto__
, 是一個(gè)對象空間
既然每一個(gè)對象都有, 實(shí)例化對象也是對象, 那么每一個(gè)實(shí)例化對象也有這個(gè)成員
這個(gè) __proto__
對象空間是給每一個(gè)對象使用的
當(dāng)你訪問一個(gè)對象中的成員的時(shí)候
- 如果這個(gè)對象自己本身有這個(gè)成員, 那么就會(huì)直接給你結(jié)果
- 如果沒有, 就回去
__proto__
這個(gè)對象空間里面找, 里面有的話就會(huì)有結(jié)果 - 未完待續(xù)...
那么這個(gè) __proto__
又指向哪里呢?
- 這個(gè)對象是由那個(gè)構(gòu)造函數(shù) new 出來的
- 那么這個(gè)對象的
__proto__
就指向這個(gè)構(gòu)造函數(shù)的prototype
function Person() {} var p1 = new Person() console.log(p1.__proto__ === Person.prototype) // true
實(shí)例化對象的 __proto__
和所屬構(gòu)造函數(shù)的 prototype
是一個(gè)對象空間
我們可以通過構(gòu)造函數(shù)名稱來向 prototype
中添加成員
對象在訪問的時(shí)候自己沒有, 可以自動(dòng)去自己的 __proto__
中查找
那么, 我們之前構(gòu)造函數(shù)的缺點(diǎn)就可以解決了
- 我們可以把函數(shù)放在構(gòu)造函數(shù)的
prototype
中 - 實(shí)例化對象訪問的時(shí)候, 自己沒有, 就會(huì)自動(dòng)去
__proto__
中找 - 那么也可以使用了
function Person() {} Person.prototype.sayHi = function () { console.log('hello Person') } var p1 = new Person() p1.sayHi()
p1
自己沒有sayHi
方法,就會(huì)去自己的__proto__
中查找p1.__proto__
就是Person.prototype
- 我們又向
Person.prototype
中添加了sayHi
方法 - 所以
p1.sayHi
就可以執(zhí)行了 - 到這里,當(dāng)我們實(shí)例化多個(gè)對象的時(shí)候,每個(gè)對象里面都沒有方法
- 都是去所屬的構(gòu)造函數(shù)的
prototype
中查找 - 那么每一個(gè)對象使用的函數(shù),其實(shí)都是同一個(gè)函數(shù)
- 那么就解決了我們構(gòu)造函數(shù)的缺點(diǎn)
function Person() {} Person.prototype.sayHi = function () { console.log('hello') } var p1 = new Person() var p2 = new Person() console.log(p1.sayHi === p2.sayHi)
p1
是Person
的一個(gè)實(shí)例p2
是Person
的一個(gè)實(shí)例- 也就是說
p1.__proto__
和p2.__proto__
指向的都是Person.prototype
- 當(dāng)
p1
去調(diào)用sayHi
方法的時(shí)候是去Person.prototype
中找 - 當(dāng)
p2
去調(diào)用sayHi
方法的時(shí)候是去Person.prototype
中找 - 那么兩個(gè)實(shí)例化對象就是找到的一個(gè)方法,也是執(zhí)行的一個(gè)方法
結(jié)論
- 當(dāng)我們寫構(gòu)造函數(shù)的時(shí)候
- 屬性我們直接寫在構(gòu)造函數(shù)體內(nèi)
- 方法我們寫在原型上
原型鏈
- 構(gòu)造函數(shù)的
prototype
是一個(gè)對象, 每一個(gè)對象又自帶__proto__
屬性 - 構(gòu)造函數(shù)的 prototype 里面的 proto 屬性又指向哪里?
一個(gè)對象所屬的構(gòu)造函數(shù)
每一個(gè)對象都有一個(gè)自己所屬的構(gòu)造函數(shù)
比如: 數(shù)組
// 數(shù)組本身也是一個(gè)對象 var arr = [] var arr1 = new Array()
- 以上兩種方式都是創(chuàng)造一個(gè)數(shù)組
- 我們就說數(shù)組所屬的構(gòu)造函數(shù)就是
Array
比如: 函數(shù)
// 函數(shù)本身也是一個(gè)對象 var fn = function () {} var fun = new Function()
- 以上兩種方式都是創(chuàng)造一個(gè)函數(shù)
- 我們就說函數(shù)所屬的構(gòu)造函數(shù)就是
Function
constructor
- 對象的
__proto__
里面也有一個(gè)成員叫做 constructor - 這個(gè)屬性就是指向當(dāng)前這個(gè)對象所屬的工造函數(shù)
鏈狀結(jié)構(gòu)
- 當(dāng)一個(gè)對象我們不知道準(zhǔn)確的是誰構(gòu)造的時(shí)候, 我們就把他看成
Object
的實(shí)例化對象 - 也就是說, 我們的 構(gòu)造函數(shù) 的 prototype 的 proto 指向的是 Object.prototype
Object.prototype
也是個(gè)對象, 那么它的__proto__
又指向誰呢?- 因?yàn)?
Object
的 js 中的頂級構(gòu)造函數(shù), 我們有一句話叫 萬物皆對象 - 所以
Object.prototype
就到頂了,Object.prototype 的 __proto__
就是 null
原型鏈的訪問原則
- 訪問一個(gè)對象的成員時(shí), 自己沒有就會(huì)去
__proto__
中找 - 接下來就是, 如果
__proto__
里沒有就再去__proto__
里面找 - 一直找到
Object.prototype
里面都沒有, 那么就會(huì)返回undefined
對象的賦值
到這里, 我們就會(huì)覺得, 如果是賦值的話, 那么也會(huì)按照原型鏈的規(guī)則來
但是: 并不是! 并不是! 并不是! 重要的事情說三遍
賦值的時(shí)候就是直接給對象本身賦值
- 如果原先有就是修改
- 如果原先沒有就是添加
- 不會(huì)和
__proto__
有關(guān)系
總結(jié)
到了這里, 我們就發(fā)現(xiàn)了面向?qū)ο蟮乃枷肽J?/p>
- 當(dāng)我想完成一個(gè)功能的時(shí)候
- 先看內(nèi)置構(gòu)造函數(shù)有沒有能給我提供一個(gè)完整功能對象的能力
- 如果沒有, 我們就自己寫一個(gè)構(gòu)造函數(shù), 能創(chuàng)造出一個(gè)完成功能的對象
- 然后再用我們寫的構(gòu)造函數(shù) new 一個(gè)對象出來, 幫助我們完成功能就行了
以上就是前端面向?qū)ο缶幊讨瓻S5語法ES6語法詳解的詳細(xì)內(nèi)容,更多關(guān)于前端面向?qū)ο缶幊蘀S5ES6語法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
微信小程序基于高德地圖API實(shí)現(xiàn)天氣組件(動(dòng)態(tài)效果)
這篇文章主要介紹了微信小程序基于高德地圖API實(shí)現(xiàn)天氣組件(動(dòng)態(tài)效果),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10firefox中用javascript實(shí)現(xiàn)鼠標(biāo)位置的定位
firefox中用javascript實(shí)現(xiàn)鼠標(biāo)位置的定位...2007-06-06uniapp使用mui-player插件播放m3u8/flv視頻流示例代碼
在小程序里播放視頻是很常見的功能,下面這篇文章主要給大家介紹了關(guān)于uniapp使用mui-player插件播放m3u8/flv視頻流的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06頁面調(diào)用單個(gè)swf文件,嵌套出多個(gè)方法。
頁面調(diào)用單個(gè)swf 文件,嵌套出多個(gè)方法,需要的朋友可以參考下。2011-11-11bootstrap table實(shí)現(xiàn)點(diǎn)擊翻頁功能 可記錄上下頁選中的行
這篇文章主要介紹了bootstrap table實(shí)現(xiàn)點(diǎn)擊翻頁功能,可記錄上下頁選中的行,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09JavaScript設(shè)置FieldSet展開與收縮
JavaScript設(shè)置FieldSet展開與收縮實(shí)現(xiàn)代碼。2009-05-05JavaScript設(shè)計(jì)模式之策略模式詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript設(shè)計(jì)模式之策略模式的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06JavaScript實(shí)現(xiàn)窮舉排列(permutation)算法謎題解答
這篇文章主要介紹了JavaScript實(shí)現(xiàn)窮舉排列(permutation)算法謎題解答,窮舉排列是指窮舉一個(gè)數(shù)組中各個(gè)元素的排列,需要的朋友可以參考下2014-12-12