面向对象编程/原型及原型链(进阶)

一.面向对象

(1)对象是什么?为什么要面向对象?

通过对代码的抽象,进而描述单个种类物体的方式.

(2)特点:面向对象-逻辑上迁移更加灵活,代码的复用性更高,高度的模块化.

(3)对象的理解

1.对象是对于单个物体的简单抽象;

2.对象是容器,封装了属性和方法

**属性:对象状态

**方法:对象的能力/行为

        //简单对象
        const Course = {
            teacher: 'tom',
            leader: 'xh',
            startCourse: name => {
                return `开始${name}课`
            }
        }
        //A同学
        Course.teacher = 'xxx'
        Course.startCourse('react')

        //B同学
        Course.startCourse('vue')  //发现即使课变了,但是老师也被修改了

        //引出函数对象
        function Course(){
            this.teacher='tom'
            this.leader='xh'
           this.startCourse= name => {
                return `开始${name}课`
            }
        } 

##构造函数

####需要一个模板-表征了一类物体的共同属性,从而生成对象.

####类即对象模板

#### js本质并不是基于类,而是基于构造函数+原型链

### Course本质就是构造函数

*1.函数体内使用的this,指向所要生成的实例;

2.生成对象用new来实例化;

3.可以初始化传参.

       function Course() {
            this.teacher = 'tom' //这里的this其实指向course 这个实例对象
            this.leader = 'xh'
            this.startCourse = name => {
                return `开始${name}课`
            }
        }
        const course = new Course(args)

####追问:如果构造函数不初始化,可以使用具有相同能力吗?->无法具有

####如果在项目中需要使用,且不希望外界进行感知情况下,如何让外界直接拿到实例化后的对象?=>单例模式

       function Course() {
            const _isClass = this instanceof Course
            //未实例化
            if (!_isClass) {
                return new Course
            }
            this.teacher = 'tom'
            this.leader = 'xh'
            this.startCourse = name => {
                return `开始${name}课`
            }
        }
        //使用方
        const course=Course()

启发:编写底层api代码时,尽量做到不让外界去感知区分内部类型.

####引发思考:new是什么?/new的原理是什么?/new的时候做了什么?

        function Course() { }
        const course = new Course()

*总结:1.结构上:创建了一个空对象,作为返回的对象实例;

2.属性上:将生成空对象的原型对象指向了构造函数的prototype属性;

3.关系上:将当前实例对象赋值给了内部的this;

4.生命周期上:执行了构造函数的初始化代码.

####追问:实例属性影响-独立的

function Course(teacher, leader) {
            this.teacher = teacher
            this.leader = leader
        }
        const course1 = new Course('tom', 'xh')//course1.teacher ->tom
        const course2= new Course('steven', 'bubu')//course2.teacher ->steven
        course2.teacher='xxx'//course.teacher=>tom
        //分析过程:course1 是构造函数的实例化对象,而this指向了这个实例化对象,所以this.teacher和this.leader 
        //是实例化对象上的属性,而构造函数new Course时,调用了Course()这个函数传入的参数,所以实例化对象的teacher
        //属性也就指向了调用Course()这个函数传入的参数.

###拔高:用js手写一个new

        function usernew(obj, ...args) {
            const newObj = Object.create(obj.prototype)
            const result = obj.apply(newObj, args)
            return typeof result === 'object' ? result : newObj
        }

 ###constructor是什么?

        function Course(teacher, leader) {
            this.teacher = teacher
            this.leader = leader
        }
        const course1 = new Course('tom', 'xh')//course1.teacher ->tom

*1.每个对象创建时,会自动拥有一个构造函数属性constructor;

2.constructor源自原型对象,指向了构造函数的引用.

*实例获得了模板的属性=>(大胆点)继承了类的属性

####原型对象

        function Course(){}
        const course1 = new Course()
        const course2 = new Course()
        //1.Course - 用来初始化创建对象的函数 | 类
        course1.__proto__===Course.prototype
        //2.course1 - 根据原型创建出来的实例
        course1.constructor===Course

*prototype是什么?

        function Course() {
            this.teacher = 'tom'
            this.leader = 'xh'
        }
        Course.prototype.startCourse = name => {
            return `开始${name}课`
        }
        const course1 = new Course()

*追问:原型对象有自己的原型链吗?

        course1.__proto__.__proto__ === Object.prototype
        Course.prototype.__proto__ === Object.prototype
        course1.__proto__.__proto__.__proto__ === null

原型链

完整的原型图:

**继承

js如何实现继承?

####在原型对象的所有属性方法,都可以被实例所共享

        function Game() {
            this.name = 'lol'
        }
        Game.prototype.getName = function () {
            return this.name
        }
        //LOL
        function LOL() { }
        LOL.prototype = new Game()//将LOL的原型对象指向Game的实例
        LOL.prototype.constructor = LOL
        const game = new LOL()

本质:重写了原型对象方式,将父对象的属性方法,作为自原型对象的属性方法,同时重写构造函数.

####追问:原型链直接继承,有什么缺点?

        function Game() {
            this.name = 'lol'
            this.skin=['s']
        }
        Game.prototype.getName = function () {
            return this.name
        }
        function LOL() { }
        LOL.prototype = new Game()//将LOL的原型对象指向Game的实例
        LOL.prototype.constructor = LOL
        const game1 = new LOL()
        const game2 = new LOL()//game2也会拿到新添加的属性值
        game1.skin.push('ss')

*1.父类属性一旦赋值给子类的原型属性,此时属性属于子类得共享属性了;

*2.实例化子类时,元素无法向父类进行传参.

###解决方法:构造函数继承

####经典继承:在子类得构造函数内部使用父类的构造函数

        function Game(args) {
            this.name = 'lol'
            this.skin = ['s']
        }
        Game.prototype.getName = function () {
            return this.name
        }
        function LOL(args) {
            Game.apply(this, args)//调用Game的this,并传递参数
        }
        const game3 = new LOL('args')

解决了共享属性问题+子向父传参的问题.

###追问::原型链上的共享方法无法被读取继承,如何解决?

####组合继承

        function Game(args) {
            this.name = 'lol'
            this.skin = ['s']
        }
        Game.prototype.getName = function () {
            return this.name
        }
        function LOL(args) {
            Game.apply(this, args)//调用Game的this,并传递参数
        }
        LOL.prototype = new Game()//调用
        LOL.prototype.constructor = LOL
        const game4 = new LOL('args')//调用

###追问:组合继承缺点?问题在于,无论何种场景,都会调用两次父类的构造函数.

###解决方案:寄生组合继承

        function Game(args) {
            this.name = 'lol'
            this.skin = ['s']
        }
        Game.prototype.getName = function () {
            return this.name
        }
        function LOL(args) {
            Game.apply(this, args)//调用Game的this,并传递参数
        }
        LOL.prototype =Object.create(Game.prototype)//关键点
        LOL.prototype.constructor = LOL
        const game5 = new LOL('args')//调用

###拔高:如何实现多重继承?

        function Game(args) {
            this.name = 'lol'
            this.skin = ['s']
        }
        Game.prototype.getName = function () {
            return this.name
        }
        function Store() {
            this.shop = 'steam'
        }
        Game.prototype.getPlatform = function () {
            return this.shop
        }
        function LOL(args) {
            Game.apply(this, args)//调用Game的this,并传递参数
            Store.apply(this, args)
        }
        LOL.prototype = Object.create(Game.prototype)//关键点
        // Store.prototype =Object.create(Game.prototype)会冲掉   LOL.prototype
        Object.assign(Store.prototype, LOL.prototype)
        LOL.prototype.constructor = LOL

猜你喜欢

转载自blog.csdn.net/huihui_999/article/details/131735721