js-面向对象编程

95 阅读2分钟

面向对象

面向过程-面向对象-面向组件-面向模块
对象:包含属性和方法

对象生成

简单对象-共享

const obj = {
	name: 'gpf',
	age: 27,
	getPro: function(newPro){
		return newPro
	}
}
    // 该对象是引用,修改会引起其他引用处的变化

构造函数生成对象

  • 函数体内生成的this指向创建的实例

  • 生成实例需要使用new进行实例化

  • 可以做初始化传参

      function  Course(){
              this.teacher = 'yunyin'
              this.leader = 'xiaowen'
              this.startCourse = function(name){
                      return name
              }
      }
      // js对象不基于类,基于构造函数+原型链
      // 生成新对象实例,实例之间不互相影响
      const course = new Course('yunyin') 
    
new的时候做了什么
  1. 创建空对象,作为返回的对象实例
  2. 将空对象的原型对象设置为构造函数的 prototype
  3. 将当前实例对象设置给内部的this
  4. 执行构造函数的初始化代码

重新构造一遍:不互相影响

构造函数执行没有意义,其中的this为window,想要使用 const course = Course()构造对象可以采用检测返回的方式

function  Course(){
        // 未实例化this指向window,实例化之后this指向当前实例
        const _isClass = this instanceof Course
        if(!_isClass){
                return new Course()
        }

        this.teacher = 'yunyin'
        this.leader = 'xiaowen'
        this.startCourse = function(name){
                return name
        }
}
constructor是什么
  1. 构造器,每个对象创建时都会有
  2. 继承自原型对象,指向构造函数的引用

构造函数继承属性会有什么性能上的问题

    // 构造函数中的方法会存在于每个实例,但方法往往不需要重复创建
    const course1 = new Course('this')
    const course2 =  new Course('OOP')
    course1.startCourse 与 course2.startCourse  重复占用空间

    构造函数的prototype === 实例的__proto__属性 相同的内存堆
    course1.constructor === Course

    解决方法:挂在共享的原型对象
            Course.prototype.startCourse = function(name){
                    return name
            }
原型链:共用原型地址,节省内存
实例的__proto__的__proto__为父级的prototype
course1.__proto__.__proto__ === Object.prototype
Object.prototype.__proto__ = null

因此Course可以使用Object的hasOwnProperty方法
另外,Course.__proto__ === Function.prototype

js实现继承

使用原型链继承父类方法

function Game(){
	this.name  = 'Game'
	this.skin = ['s']
}
Game.prototype.getName = function(){
	return this.name
}

function LOL(){}
LOL.prototype = new Game() // 直接把父类生成的实例挂在原型上
LOL.prototype.constructor =  LOL
const lol1 = new LOL();
const lol2 = new LOL();
lol1.skin.push('ss')
    

能实现继承,但两者由于原型共享而互相影响,无法分离,且无法初始化传参

    // 解决方法:组合继承
    function LOL(arg){
            Game.call(this, arg)
    }
    LOL.prototype = new Game() // 直接把父类生成的实例挂在原型上
    LOL.prototype.constructor =  LOL
    const lol3 = new LOL('lol3')
			

问题父类构造函数被执行两次 Game.call、new Game,且若有计数则计算错误

    // 解决方法:寄生组合继承
    function LOL(arg){
            Game.call(this, arg)
    }
    LOL.prototype = Object.create(Game.prototype)
    LOL.prototype.constructor =  LOL

多重继承

    function LOL(arg){
            Game.call(this, arg)
            Store.call(this, arg)
    }
    LOL.prototype = Object.create(Game.prototype)
    Object.assign(LOL.prototype, Store.prototype)
    LOL.prototype.constructor =  LOL