js面向对象基础

61 阅读3分钟

js作为一种基于对象的弱类型脚本语言,在前后端分离的今天担任着不可或缺的一部分任务,随着前端的发展,越来复杂的逻辑,让前端程序猿们不再满足于这种基于对象的编程方式,这时候js基于原型链的一种面向对象的实现方法被越来越多的人所采纳

js基于对象而不是面向对象

js是一种基于对象的语言,所谓基于对象,简单来说就是在js中有对象的概念,但是没有类的概念,学过java的人都知道,在java中,要创建一个对象实例,首先需要一个有一个这个对象的类,用类去创建这个类的对象实例,而基于对象则是用对象去创建对象。举个网上的例子:

  • 面向对象就是先设计一个房子的图纸,然后按照图纸的设计去建造一个房子

  • 基于对象就是先建造一个房子,然后根据已有的房子的样子再去建造一个房子

也就是说:

  • 面向对象: 先有一个对象的抽象描述(类),然后根据这个类去构建一个新的对象

  • 基于对象:现有一个具体对象,然后根据这个具体的对象,去创建一个新的对象

由此看来js中的所有对象都是同一个对象的子对象。

面向对象的三大基本特征:封装,多态,继承,然而基于对象和面向对象最大的区别也在这里,基于对象虽然也使用了对象,但是无法利用现有对象模板产生新的对象类型,产生新的对象,所以就没有继承这一说,没有继承也就没有多态了。

多态体现的就是继承,一般体现在抽象类上。js语言基于对象,它封装了一些对象,调用对象的方法,设置对象的属性,但是没办法产生新的类,只能使用现有的对象的方法和属性。

原型链

我们在js中创建一个对象的时候,会使用new关键字,他具体做了什么事情呢,其实他就干了三件事

    1. 创建一个空对象: var obj = {}
    1. 使这个空对象的_proto_指向基函数prototype : obj._proto_ = Basr.prototype
    1. 将基函数的this指向改为新的对象: Base.call(obj)

其实,所有的函数都是 Function 的实例。在构造函数上都有一个原型属性 prototype,该属性也是一个对象;那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;而实例对象上有一个 proto 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用。

// _proto_
在函数里有一个属性prototype
由该函数创建的对象默认会连接到该属性上
    //prototype 与 _proto_ 的关系
_proto_是站在对象角度来说的
prototype 是站在构造函数角度来说的

所谓原型链就是有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的。一个对象有原型对象,原型对象也有一个原型对象,一个对象的末级原型对象也就是Object的原型对象是null。

// 原型链示例
 7    var arr = [];
 8    arr -> Array.prototype ->Object.prototype -> null
 9    var o = new Object();
10    o -> Object.prototype -> null;

js面向对象

es5面向对象继承实现:

  function Animal() { }
  function Dog() { }
  Object.defineProperties(Animal.prototype, {
  name: {
      value() {
      return 'Animal';
      }
  },
  say: {
      value() {
      return `I ' m ${this.name()}`
      }
  }
  })
  Dog.prototype = Object.create(Animal.prototype);
  console.log(new Dog().say());  // 输出  I'm Animal

多态就是子类重写父类方法

    function Animal() { }
    function Dog() { }
    Object.defineProperties(Animal.prototype, {
    name: {
        value() {
        return 'Animal';
        }
    },
    say: {
        value() {
        return `I ' m ${this.name()}`
        }
    }
    })
    Dog.prototype = Object.create(Animal.prototype, {
        name: {
            value() {
            return 'Lucy';
            }
        }
    });
    console.log(new Dog().say());  // 输出  I'm Lucy

在es6中提供了语法糖 ,一定程度上简化了继承与多态的实现:

  class Person {
      say() {
          console.log('我姓' + this.xs);
      }
  }

  class PersonZ extends Person {
       xs = '张';
  }


  new PersonZ().say();  // 输出  我姓张