js面向对象总结

818 阅读5分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

对象

  • 对象是单个实物的抽象
  • 对象是一个容器,封装了属性方法
  • 对象可以复用,通过继承机制还可以定制

面向对象(OOP)

面向对象做了什么?

  • 将真实的世界中的各种复杂关系,抽象为一个个对象
  • 由对象之间的分工与合作,完成对真实世界的抽象

面向对象解决了什么问题?

  • 具有灵活、代码可复用、高度模块化等特点,容易维护和开发
  • 比起由一系列函数或指令组成的传统的过程式编程,更适合多人合作的大型软件项目

构造函数

什么是类?

  • 典型的面向对象的语言(eg.c++和Java)中,都有类这个概念
  • 类就是对象的模版,对象就是类的实例
  • 类可以创建任意多个具有相同属性和方法的对象

JS怎么实现"类"?

  • 通过构造函数原型链

什么是构造函数?

  • 专门用来生成实例对象的函数
  • 是对象的模版,描述实例对象的基本结构
  • 一个构造函数,可以生成多个实例,而且这些实例对象都有相同的结构

构造函数有何特点?

var Vehicle = function (p) {
  this.price = p;
};

var v = new Vehicle(500);
  • 函数体内部使用了this关键字,代表了所要生成的对象实例。
  • 生成对象的时候,必须使用new命令。

new命令做了什么?

  1. 创建一个空对象,作为将要返回的对象实例

构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。

  1. 将这个空对象的原型,指向构造函数的prototype属性
  2. 将这个空对象赋值给函数内部的this关键字
  3. 开始执行构造函数内部的代码

如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

// new的实现原理
function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) {
  // 将 arguments 对象转为数组
  var args = [].slice.call(arguments);
  // 取出构造函数
  var constructor = args.shift();
  // 创建一个空对象,继承构造函数的 prototype 属性
  var context = Object.create(constructor.prototype);
  // 执行构造函数
  var result = constructor.apply(context, args);
  // 如果返回结果是对象,就直接返回,否则返回 context 对象
  return (typeof result === 'object' && result != null) ? result : context;
}

// 实例
var actor = _new(Person, '张三', 28);

如果忘了使用new命令,直接调用构造函数会发生什么事?

  • this会指向全局

new.target的作用是什么?

  • 函数内部可以使用new.target属性
  • 如果当前函数是new命令调用,new.target指向当前函数,否则为undefined
  • 可以用来判断函数调用时是否使用了new命令
function f() {
  if (!new.target) {
    throw new Error('请使用 new 命令调用!');
  }
  // ...
}

f() // Uncaught Error: 请使用 new 命令调用!

构造函数的缺点是什么?

  • 同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费
  • 解决方法==>原型对象

原型对象&原型链

什么是原型对象?

  • 每个函数都有一个prototype属性,指向一个对象

对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型

  • 原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上

原型对象的作用,就是定义所有实例对象共享的属性和方法

什么是原型链

所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……

  • 读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined
  • 原型链的尽头就是null

constructor 属性到底是个啥?

  • prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数,可以被所有实例对象继承
function P() {}
P.prototype.constructor === P // true
  • constructor属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的
  • 有了constructor属性,就可以从一个实例对象新建另一个实例(间接调用
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true

//在实例方法中,调用自身的构造函数成为可能
Constr.prototype.createCopy = function () {
  return new this.constructor();
};

instanceof 运算符有何作用?

  • instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例

构造函数如何实现继承?

  1. 第一步是在子类的构造函数中,调用父类的构造函数
function Sub(value) {
//Sub是子类的构造函数,this是子类的实例
//在实例上调用父类的构造函数Super,就会让子类实例具有父类实例的属性
  Super.call(this);
  this.prop = value;
}
  1. 是让子类的原型指向父类的原型,这样子类就可以继承父类原型
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = '...';

未完待续

了解面向对象编程

es6 class您再瞅瞅