原型、继承及es6模块化

面向对象回顾:

  1. 通过new构造函数的方式(class的constructor (es6))
class Person{
    constructor(name){ //构造器
        this.name = name
    }
}
var person = new Person('tom')
  1. function的方式 (es3)
function Person(name){
    this.name = name
}
var person  = new Person('jack')

步骤
1、自动构建对象
2、手动设置属性
3、自动返回对象

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

步骤:
1、手动构建对象
2、手动设置属性
3、手动返回对象

构造函数的缺陷:

构造函数的缺陷:就是里面声明的函数,会在每次new的时候重新在对应的堆上开辟一个内存,这样占用的内存就很大,效率就低了。

解决方式 :找一个共享的空间(对象),只声明一次),将这个函数放进去

  • 那么现在这个共享空间应该属于构造函数
  • 这个属于构造函数的空间就被称为原型
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 对应的存储地址不一样
console.log(person.age == person1.age);//true
console.log(person.sayHello == person1.sayHello);//false 函数也是引用数据比较的是地址、

原型:

prototype

概述:prototype是属于函数的一个空间,它是一个对象。因为构造函数也是函数所以它也具备。而这个prototype属性我们称为显式原型。

函数的prototype

对应的这个prototype显示是一个对象,里面具备对应的属性及方法。主要为方法,那么也就是说这个prototype属性上一般存放对应的方法。

function fn(){

}
console.log(fn.prototype);
image.png
构造函数的prototype
function Person(){

}
console.log(Person.prototype);
//获取当前的构造函数
console.log(Person.prototype.constructor);
//将函数存储在原型上
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上存储的内容 通过实例对象.属性名访问
console.log(person.sayHello == person1.sayHello);//true
///对于prototype上存储的内容 通过实例对象.属性名访问
console.log(person.constructor);
  • 从上可得构造函数的prototype是一个对象,第二个里面有个属性 constructor指向当前的构造函数。
  • 实例对象访问对于的prototype上的内容可以通过实例对象.属性名访问
  • 一般将对应的函数存储在对应prototype上(这个函数只会声明一次)。将函数存储在原型,将属性放在构造函数里面。
  • 在prototype里面声明的函数的this指向当前的调用的实例对象

__proto__

概述:__proto__称为隐式原型,它是属于对象的一个空间,每个对象都存在这个空间,那么对应的实例对象也是一个对象,所以它也有这个空间。这个空间指向对应的构造函数的prototype。

var obj = new Object()
//每个对象都存在的一个空间 它指向对应的构造函数的prototype
console.log(obj.__proto__);
//对象的__proto__指向对应的构造函数的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__指向对应的构造函数的prototype
  • 构造函数也是一个对象,它的__proto__指向对应的父类的构造函数的prototype
  • Object的__proto__指向null
//指向Person.prototype
console.log(person.__proto__);
//指向构造函数的原型的原型 构造函数的原型是啥 是一个对象  Object.prototype
console.log(person.__proto__.__proto__);
//指向构造函数的原型的原型 构造函数的原型是啥 是一个对象  Object.prototype 的__proto__是null
console.log(person.__proto__.__proto__.__proto__);

原型链:

概述:对象在__proto__上找属性的链式结构被称为原型链。

__proto__的指向来看,对象在原型上找属性的过程为:
  • 先找自己的__proto__ (对应的构造函数的prototype)
  • 再找对应的自身构造函数的原型的__proto__ 找到父类构造函数的原型 ,再找对应的父类的原型的__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

注意事项

  • 原型链不包含对象赋值
  • 对象赋值的操作是找到这个属性了重新设置值
  • 没有找到这个属性进行,添加这个属性进行赋值操作

总结:

  • 构造函数的原型prototype
  • 实例对象的原型__proto__
  • 实例对象的__proto__指向构造函数的prototype
  • 原型链通过对应的对象的__proto__去找对应的属性 直到找到Object为止
  • 原型一般上面写函数,可以保证函数只声明一次。对应的属性写在构造函数内。
  • 原型上的方法/属性。通过实例对象.属性名直接访问(平常通过对象去点的方法都称为原型方法)
  • 在对应的原型上的函数里面的this指向当前调用的实例对象

通过原型来实现数组的高阶函数

forEach实现和map实现
//数组的原型
//在数组的原型上添加一个myForEach的方法
//在对应的原型上的函数里面的this指向当前调用的实例对象
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实现
//回调函数  defaultValue初始值
Array.prototype.myReduce = function(fn,defaultValue){
    //默认请求 前面的值为第一个开始下标为第二个
    let previousValue = this[0]
    let index = 1
    //如果传了初始值 那么对应的初始值为传入的值 开始的下标从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
}

面向对象的三大特性:

  • 封装 (函数的抽取,属性的抽取)
  • 继承 (子类继承父类)
  • 多态 (重写,子类重写父类方法)

继承

概述:子类继承父类的属性和方法(非私有的属性和方法,非静态的方法)

继承的实现:
  1. 使用extends关键词实现继承(类的继承、es6新增)
// es6新增类的继承 extends关键词实现
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. 原型链继承 (覆盖之前原型上的所有方法 显示的时候不会显示继承来的属性 (在原型上重复出现一样的属性))
    核心:在子类的原型上创建父类的对象
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指向,在子类中调用父类的构造函数
function Person(){
    this.name = 'jack'
}
function Son(age){
    //改this指向 执行父类的构造函数
    Person.call(this)
    this.age = age
}
var son = new Son(18)
console.log(`son`, son);
  1. 组合继承 (使用原型链继承和对象冒充结合)
// 组合继承 原型链继承加对象冒充
function Person(){
    this.name = 'jack'
}
Person.prototype.say = ()=>{
    console.log(`hello`);
}
function Son(age){
    //改this指向 执行父类的构造函数
    Person.call(this)
    this.age = age
}
//原型链继承
Son.prototype = new Person()
var son = new Son(18)
console.log(`son`, son);
son.say()
  1. 组合寄生继承 (对象冒充 + 原型链继承(创建一个原型对象放在原型链上))
  • 对象冒充
  • 在子类的原型上创建父类的原型对象
//组合寄生继承
function Person(){
    this.name = 'jack'
}
Person.prototype.say = ()=>{
    console.log(`hello`);
}
function Son(age){
    //改this指向 执行父类的构造函数
    Person.call(this)
    this.age = age
}
//寄生
Son.prototype = Object.create(Person.prototype)
var son  = new Son(18)
console.log(`son`, son);

ES6的模块化

概述:模块的思想,将对应的功能代码封装为一个模块(包含js代码、css代码、 html代码)。
注意:

  • 想要使用别人就导入,想要给别人用就导出。复用性强。
模块化的常用的模式:
  • amd (在对应的加载之前导入)
  • cmd (在用的时候导入)
  • comment.js (基于amd和cmd之上)
es6的模块化的关键词(要想导入,必须先导出)
  • import 导入
  • export 导出
export的使用(三种方式):
  1. 导出:export default (只能声明一次)
//默认导出只有一个 如果使用export default 导出的可以使用对应的一个名字来接
export default {
   obj,
   str,
   say
}

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

import obj from './test.js'
console.log(obj) //{obj,str,say}
  1. 导出:export
//如果直接使用的对应的export 导出那么必须通过{键}来接
export const obj = {
    name:'jack',
    age:18
}
//如果导出的是值类型 一定要写变量名
export const str = "你好世界"
export const say = ()=>{
    console.log('hello world');
}

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

 import {obj,str,say} from './test.js'
  1. 导出:export {只能写变量}
const name = 'tom'
//第三种导出
export {
    //只能写变量
    name
}

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

import {name} from './test.js'
import使用:
import 名字 from '地址'
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容