面向对象

97 阅读6分钟

面向对象

    面向对象是一种编程思想,不是语法
    面向对象就是对面向过程的封装

创建对象的方式

  • 面向对象就是一个找到对象的过程,所以我们要先创建一个对象
1、字面量创建
    var obj = {}
    obj.name = 'QF'
2、内置构造函数创建对象
var obj = new object()
obj.name = 'QF'
3、使用工厂函数创建对象
  • 先写一个工厂函数
  • 这个工厂函数当中可以创建一个对象,并且给对象添加一些属性
  • 使用这个工厂函数创建的函数
//1、创建一个工厂函数
    //1.1手动创建对象
    //2.2手动向对象中添加成员
    //3、手动返回一个对象

function createObj(){
    //1.1手动创建对象
    var obj = new Object()
    //2.2手动向对象中添加成员
    obj.name = 'QF'
    obj.age = 18
    //3、手动返回一个对象
    return obj
}
//使用:
    var o1 = createObj()
    var o2 = createObj()
4、使用自定义构造函数创建对象
  •   创建过程:
          1、自动创建对象(不用写)
          2、手动添加对象(需要我们自己添加)
          3、自动返回对象(不用写)
    
  • 创造一个构造函数

    1、先书写一个构造函数
    2、在构造函数内相对象添加一些成员
    3、使用这个构造函数创建一个对象(和new连用)
    4、构造函数可以创建对象,并且创建一个带有属性和方法的对象
    5、面向对象就是要想办法找到一个有属性的方法的对象
    6、面向对象就是我们自己制造构造函数的过程
    
function Person(name,gender){
    this.age = 10
    this.name = name
}
//创建一个新对象
var p1 = new Person('jack','man')
var p2 = new Person('rose','woman')

构造函数的基本使用

*   1、不写new 的时候就是普通函数调用
    2、首字母不大写,只要和new连用,就有创造一个对象的能力
    3、当调用的时候,如果不需要传递参数可以不写(),但建议写上
    var o1 = new person
    4、构造函数内部this,由于和new连用的关系,是指向当前实例对象
    5、因为构造函数会自动返回一个对象,所以构造函数内部不要写return
            return 一个基本数据类型。写了和没写一样
            return 一个引用数据类型时,返回引用数据类型,此时构造函数无意义了
  • 当通过new关键字实例化对象调用时,每个都有的成员

  • 我们可以通过构造函数添加一些方法

  • 但是在通过new调用时会创建出不同的函数,如果指向的都是同一个地址的内容,那么会出现空间上的浪费。

prototype(针对函数)
  • 每个函数天生自带一个成员,叫做prototype,是一个对象空间
  • 既然每个函数都有,构造函数也有
  • 这个prototype对象空间可以通过函数名来访问
function Person(){}
console.log(Person.prototype)//是一个对象
  • 既然是对象,可以向里面添加一些方法
  • 注意:prototype里面的东西不是给函数使用的,是给每一个实例化对象使用的
proto(针对对象)
  • 每个对象都天生自带一个成员,叫做__proto__,是一个对象空间

  • 通过new关键字实例化对象也是一个对象,所以实例化对象也有这个成员

  • __proto__是给每一个对象空间成员使用的

  • 当访问一个对象中的成员的时候

    • 如果这个对象自己有这个成员,那么直接反馈
    • 如果没有,会去__proto__当中寻找。。。
  • __proto__指向哪?

    • 这个对象是由构造函数实例化出来的
    • 所以这个对象的__proto__就指向这个构造函数的prototype
function Person() {}
var p1 = new Person()
console.log(p1.__proto__ === Person.prototype)  // true
利用prototype解决内存空间浪费的问题
  • 实例化对象的__proto__和所属构造函数的prototype是一个对象空间。
  • 我们可以通过构造函数名称来向 prototype 中添加成员
  • 对象在访问的时候自己没有, 可以自动去自己的 __proto__ 中查找
  • 那么, 我们之前构造函数的缺点就可以解决了
    • 我们可以把函数放在构造函数的 prototype
    • 实例化对象访问的时候, 自己没有, 就会自动去 __proto__ 中找
    • 那么也可以使用了
function Person() {}

Person.prototype.sayHi = function () {
    console.log('hello Person')
}

var p1 = new Person()
p1.sayHi()  //

先去p1当中查找,p1当中没有sayHi()这个方法,向自己的`__proto__`中查找
`p1.__proto__`就是`Person.prototype`中添加`sayHi`方法
所以p1.sayHi能正常执行了

原型

  • 每一个函数都有数以自己的原型 作用:我们会在原型内部放一些公共的方法,目的不是为了给构造函数去使用,而是为了让实例化对象去使用的。

    任何一个数组的构造函数都是Array 任何一个对象的构造函数都是Object 任何一个函数的构造函数都是Function

js中,万物都可以成为对象

对象:含义1:一种数据格式{key:value,key2:value}
      含义2:某一类事物的实例(某一类内容中的真实个体)

*   如果一个数据 [] 那么他就是Array 这个对象中的某一个个体
*  如果一个数据 {} 那么他就是Object 这个对象中的某一个个体
*  如果一个数据 function(){}   那么他就是 Function 这个对象中的某一个个体

原型链

查找对象的某一个属性:
现在对象内部查找,找到直接使用,然后停止查找

如果没有找到,会找对象的obj.__proto__
.
.
直到找到顶层作用对象    Object.prototype,找到使用,找不到undefined
function Person(name){
    this.name = name
}
Person.prototype.sayHi = function (){
    console.log(100)
}
const p = new Person('QF001')

问题一:p的__proto__指向谁

    p是实例化对象
    __proto__指向自身构造函数的原型
    所以 p.__proto__ === Person.prototype

问题二:Person的__proto__指向谁

    Person是构造函数,本身就是一个函数
    Person.__proto__指向它自身构造函数的原型
    所以:Person.__proto__ === Function.prototype

问题三:Person.prototype的__proto__指向谁

    Person.prototypep指向Person的原型,原型就是一个对象
    Person.prototype.__proto__指向它自身构造函数的原型
    所以:Person.prototype.__proto__ === Object.prototype

问题四:Function的__proto__指向谁

    Function本质上就是一个函数
    Function.__proto__指向它自身构造函数的原型
    所以:Function.__proto__ === Function.prototype

问题五:Function.prototype的__proto__指向谁

    Function.prototype指向Function的原型,原型是一个对象
    Function.prototype.__proto__指向自身构造函数的原型
    所以:Function.prototype.__proto__ === Object.prototype

问题六:Object的__proto__指向谁?

    Object是一个构造函数,本质上是一个函数
    Object.__proto__只想自身构造函数的原型
    所以:Object.__proto__ === Function.prototype

问题七:Object.prototype的__proto__指向谁?

    Object.prototype是一个对象,但是此时他为顶层对象
    所以:Object.prototype.__proto__ === null
判断数据类型
  1. typeof 判断基本数据类型

  2. constructor 可以判断 当前数据的 构造函数 是谁

     问题1: 能够判断引用数据类型
             但是! 这个属性其实就是对象内的一个属性
                       我们可以拿到这个对象, 然后修改他的属性值
               问题2: 不能判断 undefinednull
    
    1. instanceof 可以判断 左边的构造函数是否等于右边的构造函数
  •    语法: 检测的数据 instanceof 构造函数
        问题: 不能判断 undefinednull
    
    1. Object.prototype.toString.call(要判断的数据结构)
  •   Object 这个构造函数的 原型内部 有一个 toString 的方法
      这个方法能够帮我们将数据结构转为字符串的形式    '[object 数据结构]'
    
       我们在使用的时候 如果需要判断其他数据类型, 需要使用 .call这个方法改变内部 this 指向
       这个方法任何数据类型都能准确判断(推荐使用)