面向对象

179 阅读7分钟

面向对象

  • OOA面向对象分析
  • OOD面向对象设计
  • OOP面向对象编程

面向对象是一种编程思维(oop),将对应的你需要用到的对象进行提取,将对应方法综合到对应的对象中,在需要调用对应的方法的时候去找对应的对象。(万物皆对象(任何东西都可以抽取为对象),主要的过程就是找对应的对象做对应的事情。)

面向对象是利用对象进行编程的一种思想. 面向对象又被成为 OOP (Object Oriented Programming面向对象编程)

  • 为什么要使用面向对象编程?

这种编程方式,更加贴近现实;

  • 哪些语言是面向对象?

    java,c#, c++ , js .. 面向对象编程,是主流;

什么是面向过程?它和面向对象有什么区别?

面向过程:

就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现, 使用的时候一个一个依次调用就可以了。

面向对象:

是把构成问题的事务分解成各个对象,每个对象都有自己独立的属性和行为, 对象可以将整个问题事务进行分工, 不同的对象做不同的事情, 这种面向对象的编程思想由于更加贴近实际生活, 所以被计算机语言广泛应用。

js有2种编程模式

1.面对过程 2.面向对象

面向对象的核心就是找对象

面向对象的三大特性

  • 封装 (将对应的属性和方法抽取封装到对应的类(构造函数)中)
  • 继承 (子类继承父类 子类拥有父类非私有属性及方法)
  • 多态 (一个东西多种形态体(基于继承的) 重载overload(一个类多个函数重名(js中不允许重载),同名不同参) 重写override(子类重写父类的属性和方法,基于继承的前提))

面向对象的优势:

易复用,易维护,易扩展,低耦合.

构造函数

从类(class)变成对象(object)的过程叫做构造 使用new关键词来构造 new关键词调用的函数被称为构造函数,构造函数首字母必须大写

注意:构造函数中的this指向实例化对象!

类和对象的关系

类是对象的抽象,而对象是类的具体实例

类是抽象的,不占用内存,而对象是具体的,占用存储空间。

类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。

类与对象的关系就如模具和铸件的关系

类的实例化结果就是对象,而对一类对象的抽象就是类

总结:

对象是具体的,类是抽象的,对象是类的实例,类是对象的模板,

new 可以改变this指向,指向实例对象

new操作符做了什么?

  • 在函数内部创建一个空对象

  • 空对象指针指向函数的原型

  • this指向空对象

  • 往空对象上添加属性和方法

  • 隐式的return this

  • 在函数内部创建一个空对象

var obj=new Object()
  • 空对象指针指向函数的原型
obj.__proto__=构造函数.prototype
  • this指向空对象
Person.call(obj.xxx)
  • 往空对象上添加属性和方法
this.name=xxx;this.age=xxx;如同obj.name
  • 隐式的return this
this指向obj

构造函数的声明方式

  • 使用new关键词来声明 (实际调用的都是构造函数)
var obj=new Object()
  • es6新增的class (其实调用也是构造函数)
class Person{
    //类的构造器
    constructor(name){
        this.name = name
    }
}
//调用类中的构造器
let person = new Person('jack')
  • es3自带的构造函数
function Person(name){
    this.name = name
}
let person = new Person('tom')

构造函数和class的区别

  • 构造函数的兼容会比class要好
  • 构造函数会进行预编译 class不会进行预编译,class是一个独立的代码片段
  • 构造函数他可以当作普通函数调用 class不行(需要new)
  • class默认使用的是严格模式

new构造函数的时候主要过程

  • 自动创建对象
  • 手动属性赋值
  • 自动返回对象

工厂模式

为了解决多个类似对象声明的问题我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复代码的问题,解决重复创建相同的对象,采用工厂模式

但是工厂模式虽然解决了重复实例化的问题,但是还是有一个问题,那就是识别问题,根本无法搞清楚他们到底是哪个对象的实例

工厂模式不需要new关键词

使用工厂函数的主要过程
  • 手动创建对象
  • 手动属性赋值
  • 手动返回对象
function createFacotry(name,age){
    var o=new Object();
    o.name=name;
    o.age=age;
    o.run=function(){
        
    }
    return o;
}
var dog1=createFacotry("小白",3)
var dog2=createFacotry("小黄",4)
console.log(dog1)//{name: "小白", age: 3, run: ƒ}
console.log(dog2)//{name: "小黄", age: 4, run: ƒ}

原型

函数的原型(prototype)

每个函数自带一个属性(prototype),它的值是一个对象

函数属于引用类型,每当new一个person就会创建一个新的函数

概述

prototype是函数内的一个对象空间,每个函数都有一个,他被称为显式原型

每个函数自带一个属性(prototype),它的值是一个对象

prototype只声明一次,会跟函数预编译一起声明,是一个函数内的一个对象空间(公共空间),每个函数都有一个,可以解决对应的构造函数的缺陷

作用:

为构造函数添加公共共享属性和方法,从而减少内存的开销;

构造函数的属性和方法优先于原型的属性和方法

注意:构造函数中的this

应用:

  • 对应的构造函数也属于函数 那么他同样也拥有一个prototype,且对应的prototype只有一个也就是说他会在预编译时候声明一次,也就是prototype是对应的一个构造函数的公共空间,且他只声明一次 那么也就说他就可以解决对应的构造函数的缺陷了。
function Person(){
	this.name = 'jack'
}
//构造函数的prototype空间
console.log(Person.prototype) 
  • 从上可得对应的函数的prototype这个空间他其实是一个对象,那么我们是不是可以在这个对象里面存入对应的函数
//构造函数的属性
//1.写在构造函数的内部
//2.方法可以添加到原型上(减少内存的开销)
function Person(name, age, sex) {
	this.name = name;
	this.age = age;
	this.sex = sex;
	this.family = ["爸爸", "妈妈"]
	}
Person.prototype.add = function (name) {//公共的
 	this.family.push(name)
}
var p1 = new Person("不知名选手铉", 19, '男')
p1.add("刘亦菲")
var p2 = new Person("李原凡", 19, '男')
p2.add("范冰冰")
console.log(p1.family); //["爸爸", "妈妈", "刘亦菲"]
console.log(p2.family); //["爸爸", "妈妈", "范冰冰"]
 console.log(p1.add === p2.add);//true

以上代码发现 对应的函数的prototype中存入的属性 可以直接通过对应的实例.属性来访问

原型添加方法

 function Person() {
            this.name = name
        }
        Person.prototype.eat = function () {
            console.log(this);
        }
        Person.prototype.run = function () {
            console.log(this);
        }
        Person.prototype.sleep = function () {
            console.log(this);
        }
        Person.prototype.jump = function () {
            console.log(this);
        }
        console.log(Person.prototype);//{eat: ƒ, run: ƒ, sleep: ƒ, jump: ƒ, constructor: ƒ}

        //如果需要批量添加原型方法,可以给一个新对象,但是新对象里需要手动添加构造器(constructor)

        Person.prototype = {
            //强行添加构造器,让构造器执行当前的构造函数
            constructor: Person,
            eat() {
                console.log(this);
            },
            run() {
                console.log(this);
            },
            sleep() {
                console.log(this);
            },
            jump() {
                console.log(this);
            }
        }
console.log(Person.prototype);
//{constructor: ƒ, eat: ƒ, run: ƒ, sleep: ƒ, jump: ƒ}

与this相关的知识

  • 1.事件绑定的函数里的this ,指向当前的事件绑定源
  • 2.函数里的this ,默认是window ,在ES5的严格模式,是undef ined
  • 3.对象的方法里的this,指向当前的对象
  • 4.箭头函数的this ,指向上下文对象(环境对象)
    1. new操作符改变构造函数的this指向,默认this指向window
  • 6.定时器与延时器里的this ,默认是window
    1. bind, call, apply改变this指向,但是它不能改变箭头函数的this指向