原型、繼承及es6模塊化

面向?qū)ο蠡仡櫍?/h4>
  1. 通過new構(gòu)造函數(shù)的方式(class的constructor (es6))
class Person{
    constructor(name){ //構(gòu)造器
        this.name = name
    }
}
var person = new Person('tom')
  1. function的方式 (es3)
function Person(name){
    this.name = name
}
var person  = new Person('jack')

步驟
1、自動構(gòu)建對象
2、手動設(shè)置屬性
3、自動返回對象

  1. 通過工廠模式
function factory(name){
    var obj = new Object()
    obj.name = name
    return obj
}

步驟:
1、手動構(gòu)建對象
2、手動設(shè)置屬性
3、手動返回對象

構(gòu)造函數(shù)的缺陷:

構(gòu)造函數(shù)的缺陷:就是里面聲明的函數(shù),會在每次new的時候重新在對應(yīng)的堆上開辟一個內(nèi)存,這樣占用的內(nèi)存就很大,效率就低了。

解決方式 :找一個共享的空間(對象),只聲明一次),將這個函數(shù)放進(jìn)去

  • 那么現(xiàn)在這個共享空間應(yīng)該屬于構(gòu)造函數(shù)
  • 這個屬于構(gòu)造函數(shù)的空間就被稱為原型
function Person(name){
    this.name = name
    this.age = 18
    this.sayHello = ()=>{
        console.log('hello');
    }
}
var person = new Person('jack')
var person1 = new Person('tom')
console.log(person == person1);//false 對應(yīng)的存儲地址不一樣
console.log(person.age == person1.age);//true
console.log(person.sayHello == person1.sayHello);//false 函數(shù)也是引用數(shù)據(jù)比較的是地址、

原型:

prototype

概述:prototype是屬于函數(shù)的一個空間,它是一個對象。因為構(gòu)造函數(shù)也是函數(shù)所以它也具備。而這個prototype屬性我們稱為顯式原型。

函數(shù)的prototype

對應(yīng)的這個prototype顯示是一個對象,里面具備對應(yīng)的屬性及方法。主要為方法,那么也就是說這個prototype屬性上一般存放對應(yīng)的方法。

function fn(){

}
console.log(fn.prototype);
image.png
構(gòu)造函數(shù)的prototype
function Person(){

}
console.log(Person.prototype);
//獲取當(dāng)前的構(gòu)造函數(shù)
console.log(Person.prototype.constructor);
//將函數(shù)存儲在原型上
Person.prototype.sayHello = ()=>{
    console.log(this);
}
//新建對象
var person = new Person()
var person1 = new Person()
console.log(person == person1);//false
//person.sayHello ===>   Person.prototype.sayHello
//對于prototype上存儲的內(nèi)容 通過實例對象.屬性名訪問
console.log(person.sayHello == person1.sayHello);//true
///對于prototype上存儲的內(nèi)容 通過實例對象.屬性名訪問
console.log(person.constructor);
  • 從上可得構(gòu)造函數(shù)的prototype是一個對象,第二個里面有個屬性 constructor指向當(dāng)前的構(gòu)造函數(shù)。
  • 實例對象訪問對于的prototype上的內(nèi)容可以通過實例對象.屬性名訪問
  • 一般將對應(yīng)的函數(shù)存儲在對應(yīng)prototype上(這個函數(shù)只會聲明一次)。將函數(shù)存儲在原型,將屬性放在構(gòu)造函數(shù)里面。
  • 在prototype里面聲明的函數(shù)的this指向當(dāng)前的調(diào)用的實例對象

__proto__

概述:__proto__稱為隱式原型,它是屬于對象的一個空間,每個對象都存在這個空間,那么對應(yīng)的實例對象也是一個對象,所以它也有這個空間。這個空間指向?qū)?yīng)的構(gòu)造函數(shù)的prototype。

var obj = new Object()
//每個對象都存在的一個空間 它指向?qū)?yīng)的構(gòu)造函數(shù)的prototype
console.log(obj.__proto__);
//對象的__proto__指向?qū)?yīng)的構(gòu)造函數(shù)的prototype
console.log(obj.__proto__ == Object.prototype);
function Person(){

}
var person = new Person()
console.log(person.__proto__ == Person.prototype);
// Person.prototype.sayHello = ()=>{

// }
person.__proto__.sayHello = ()=>{
    console.log('hello');
}
person.sayHello()
__proto__的指向:
  • __proto__指向?qū)?yīng)的構(gòu)造函數(shù)的prototype
  • 構(gòu)造函數(shù)也是一個對象,它的__proto__指向?qū)?yīng)的父類的構(gòu)造函數(shù)的prototype
  • Object的__proto__指向null
//指向Person.prototype
console.log(person.__proto__);
//指向構(gòu)造函數(shù)的原型的原型 構(gòu)造函數(shù)的原型是啥 是一個對象  Object.prototype
console.log(person.__proto__.__proto__);
//指向構(gòu)造函數(shù)的原型的原型 構(gòu)造函數(shù)的原型是啥 是一個對象  Object.prototype 的__proto__是null
console.log(person.__proto__.__proto__.__proto__);

原型鏈:

概述:對象在__proto__上找屬性的鏈?zhǔn)浇Y(jié)構(gòu)被稱為原型鏈。

__proto__的指向來看,對象在原型上找屬性的過程為:
  • 先找自己的__proto__ (對應(yīng)的構(gòu)造函數(shù)的prototype)
  • 再找對應(yīng)的自身構(gòu)造函數(shù)的原型的__proto__ 找到父類構(gòu)造函數(shù)的原型 ,再找對應(yīng)的父類的原型的__proto__,直到找到object為止
  • 在Object的原型的__proto__(null)上還找不到就返回undefined
    Object.prototype.hello = '你好'
    class Person{
        constructor(){
            this.name = '張三'
        }
    }
    Person.prototype.sex = '女'
    Person.prototype.username = 'rose'
    //對象賦值 有就重新賦值 沒有就添加屬性賦值
    Person.hi = '你好嗎'
    var person = new Person()
    person.age = '109'
    class Son extends Person{
        constructor(){
            super()
            this.age = '李四'
        }
    }
    Son.prototype.sex = '男'
    //實例化對象
    var son = new Son()
    console.log(son.age);//李四
    console.log(son.name);//張三
    console.log(son.username);//rose
    console.log(son.sex);//男
    console.log(son.hello);//你好 
    console.log(son.hi);//undefined
    
image.png

注意事項

  • 原型鏈不包含對象賦值
  • 對象賦值的操作是找到這個屬性了重新設(shè)置值
  • 沒有找到這個屬性進(jìn)行,添加這個屬性進(jìn)行賦值操作

總結(jié):

  • 構(gòu)造函數(shù)的原型prototype
  • 實例對象的原型__proto__
  • 實例對象的__proto__指向構(gòu)造函數(shù)的prototype
  • 原型鏈通過對應(yīng)的對象的__proto__去找對應(yīng)的屬性 直到找到Object為止
  • 原型一般上面寫函數(shù),可以保證函數(shù)只聲明一次。對應(yīng)的屬性寫在構(gòu)造函數(shù)內(nèi)。
  • 原型上的方法/屬性。通過實例對象.屬性名直接訪問(平常通過對象去點的方法都稱為原型方法)
  • 在對應(yīng)的原型上的函數(shù)里面的this指向當(dāng)前調(diào)用的實例對象

通過原型來實現(xiàn)數(shù)組的高階函數(shù)

forEach實現(xiàn)和map實現(xiàn)
//數(shù)組的原型
//在數(shù)組的原型上添加一個myForEach的方法
//在對應(yīng)的原型上的函數(shù)里面的this指向當(dāng)前調(diào)用的實例對象
Array.prototype.myForEach = function(fn){
    //遍歷
    for(let i=0;i<this.length;i++){
        fn(this[i],i,this)
    }
}
Array.prototype.myMap = function(fn){
    let returnArr = []
    //遍歷
    for(let i=0;i<this.length;i++){
        returnArr.push(fn(this[i],i,this)) 
    }
    return returnArr
}
reduce實現(xiàn)
//回調(diào)函數(shù)  defaultValue初始值
Array.prototype.myReduce = function(fn,defaultValue){
    //默認(rèn)請求 前面的值為第一個開始下標(biāo)為第二個
    let previousValue = this[0]
    let index = 1
    //如果傳了初始值 那么對應(yīng)的初始值為傳入的值 開始的下標(biāo)從0開始
    if(typeof defaultValue != 'undefined'){
        previousValue = defaultValue
        index = 0
    }
    //遍歷
    for(let i=index;i<this.length;i++){
        previousValue = fn(previousValue,this[i],i,this)
    }
    return previousValue
}

面向?qū)ο蟮娜筇匦裕?/h4>
  • 封裝 (函數(shù)的抽取,屬性的抽?。?/li>
  • 繼承 (子類繼承父類)
  • 多態(tài) (重寫,子類重寫父類方法)

繼承

概述:子類繼承父類的屬性和方法(非私有的屬性和方法,非靜態(tài)的方法)

繼承的實現(xiàn):
  1. 使用extends關(guān)鍵詞實現(xiàn)繼承(類的繼承、es6新增)
// es6新增類的繼承 extends關(guān)鍵詞實現(xiàn)
class Person{
    constructor(){
        this.name = 'jack'
    }
}
class Son extends Person{
    constructor(age){
        super()
        this.age = age
    }
}
var son = new Son(18)
console.log(`son`, son);
  1. 原型鏈繼承 (覆蓋之前原型上的所有方法 顯示的時候不會顯示繼承來的屬性 (在原型上重復(fù)出現(xiàn)一樣的屬性))
    核心:在子類的原型上創(chuàng)建父類的對象
function Person(){
    this.name = 'jack'
}
function Son(age){
    this.age = age
}
Son.prototype.say = ()=>{
    console.log(`你好`);
}
//原型繼承
// 將要繼承的類放在繼承的子類的原型上
//原型鏈會覆蓋原本原型上的私有的方法及屬性
Son.prototype = new Person()
var son = new Son(18)
console.log(`son`, son);
console.log(son.name);
// son.say() 
  1. 對象冒充 (會顯示繼承的屬性,不能繼承原型上的方法)
    核心:更改this指向,在子類中調(diào)用父類的構(gòu)造函數(shù)
function Person(){
    this.name = 'jack'
}
function Son(age){
    //改this指向 執(zhí)行父類的構(gòu)造函數(shù)
    Person.call(this)
    this.age = age
}
var son = new Son(18)
console.log(`son`, son);
  1. 組合繼承 (使用原型鏈繼承和對象冒充結(jié)合)
// 組合繼承 原型鏈繼承加對象冒充
function Person(){
    this.name = 'jack'
}
Person.prototype.say = ()=>{
    console.log(`hello`);
}
function Son(age){
    //改this指向 執(zhí)行父類的構(gòu)造函數(shù)
    Person.call(this)
    this.age = age
}
//原型鏈繼承
Son.prototype = new Person()
var son = new Son(18)
console.log(`son`, son);
son.say()
  1. 組合寄生繼承 (對象冒充 + 原型鏈繼承(創(chuàng)建一個原型對象放在原型鏈上))
  • 對象冒充
  • 在子類的原型上創(chuàng)建父類的原型對象
//組合寄生繼承
function Person(){
    this.name = 'jack'
}
Person.prototype.say = ()=>{
    console.log(`hello`);
}
function Son(age){
    //改this指向 執(zhí)行父類的構(gòu)造函數(shù)
    Person.call(this)
    this.age = age
}
//寄生
Son.prototype = Object.create(Person.prototype)
var son  = new Son(18)
console.log(`son`, son);

ES6的模塊化

概述:模塊的思想,將對應(yīng)的功能代碼封裝為一個模塊(包含js代碼、css代碼、 html代碼)。
注意:

  • 想要使用別人就導(dǎo)入,想要給別人用就導(dǎo)出。復(fù)用性強(qiáng)。
模塊化的常用的模式:
  • amd (在對應(yīng)的加載之前導(dǎo)入)
  • cmd (在用的時候?qū)耄?/li>
  • comment.js (基于amd和cmd之上)
es6的模塊化的關(guān)鍵詞(要想導(dǎo)入,必須先導(dǎo)出)
  • import 導(dǎo)入
  • export 導(dǎo)出
export的使用(三種方式):
  1. 導(dǎo)出:export default (只能聲明一次)
//默認(rèn)導(dǎo)出只有一個 如果使用export default 導(dǎo)出的可以使用對應(yīng)的一個名字來接
export default {
   obj,
   str,
   say
}

接收:import 名字 from './test.js'

import obj from './test.js'
console.log(obj) //{obj,str,say}
  1. 導(dǎo)出:export
//如果直接使用的對應(yīng)的export 導(dǎo)出那么必須通過{鍵}來接
export const obj = {
    name:'jack',
    age:18
}
//如果導(dǎo)出的是值類型 一定要寫變量名
export const str = "你好世界"
export const say = ()=>{
    console.log('hello world');
}

接收:import {方法名} from './test.js'

 import {obj,str,say} from './test.js'
  1. 導(dǎo)出:export {只能寫變量}
const name = 'tom'
//第三種導(dǎo)出
export {
    //只能寫變量
    name
}

接收:import {變量名} from './test.js'

import {name} from './test.js'
import使用:
import 名字 from '地址'
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容