5

经过面试的挫折之后,继续深入学习~~

1、原型概念的提出

传统的构造函数对象包含方法时,在构造函数创建时,就会将所有内容重新创建一次,导致数据的重复,代码的冗余,如下所示:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = function () {
    console.log("Hello");
  }
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 结果为false,因为p1,和p2的sayHello虽结构一样,但却是两个不同的对象

改良1:将方法提取到外面

function sayHello(){
  console.log("Hello");
}
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = sayHello;
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 结果为true,但当代码量不断增加,自定义的函数越来越多时,可能会和框架中的函数发生命名冲突,也不利于代码的维护

改良2:将方法放到构造函数中,且避免命名冲突,原型概念出现

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function (){
   console.log("Hello");
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 结果为true

构造函数一旦被创建,就会有一个原型属性,也是个对象,可以往里面添加成员,每个由构造函数创建出来的对象都会默认连接到原型属性上去。

当js引擎查找对象属性时,会先查找对象上是否具有该属性,如果没有,就会去原型属性上去查找。

所以,什么是原型?原型是能够实现继承的,当构造函数被定义的时候,原型也就被创建出来,它可以存储属性和方法,既是一个属性也是一个对象。当构造函数创建的实例对象需要访问某个方法或属性,而这个对象又没有该方法或属性的时候,它会去原型上面去查找。也就是实例对象访问原型对象的属性或调用原型对象的方法,说的通俗一点也就是把别的对象的方法或属性拿过来自己用,就是继承,所以我们也可以说对象继承自其原型。

引入:属性查找机制:对象在访问属性或方法时,首先在当前对象查找,如果该对象有该属性或方法,则停止查找,如果没有,则去原型中查找,如果原型没有,则去原型的原型中查找,直到原型的顶部,如果还是没有,则返回undefined(属性)或 xxx is not a function(方法)

2、一些相关概念

① 面向对象的相关概念

  • 类class:在js中就是构造函数
  • 实例(instance)与对象(object)
    实例是指某个构造函数创建出来的对象,我们称之为xxx构造函数的实例;
  • 键值对与属性和方法
    在js中,键值对的集合称之为对象
    如果数据是值,该键值对为属性prototype
    如果数据是函数,该键值对为方法method
  • 父类与子类
    js中没有class的概念,由C++引申过来,父类又称基类,子类又称派生类
    js中称为父对象、子对象

② 原型的相关概念

  • prototype针对构造函数,称为“原型属性”
  • prototype针对构造函数创建出来的对象,称为“原型对象”
  • 原型属性与原型对象的关系:
    !!构造函数的原型属性和构造函数创建出来的对象的原型对象,是一个东西
    !!构造函数的原型属性所指向的对象,与构造函数创建出来的对象(实例对象),这是两个不同的对象(快绕晕了)

3、对象继承自其原型

构造函数创建出来的对象(实例对象)继承构造函数的原型属性和原型对象

4、原型的使用

  • 利用对象的动态特性:在原来的对象上添加成员
    构造函数.prototype.xxx = ccc;
  • 直接替换:重新创建一个对象
    构造函数.prototype = {};

5、__proto__

通过 proto 允许实例对象直接访问原型,通常用于在调试中查看原型的成员(实例对象不允许修改原型)

6、原型的结构

有一个默认属性:constructor => 构造器,表示该原型是与什么构造函数联系起来的
∴ 构造函数通过 prototype 的属性访问原型,原型可以通过 constructor 访问构造函数

7、继承

  • 简单继承:将别的对象的方法或属性直接拿过来,加到自己身上,于是我就有了该方法或属性。=> 简单粗暴,层次清晰
  • 利用原型继承:不需要添加成员,只要原型具有,我便有了。=> 提高复用性
  • 混合式继承:将方法或属性利用混入的方法,加到构造函数原型中,实例对象即有了指定的方法或属性。

8、静态成员和实例成员的概念

该概念由其他面向对象的语言引入。

  • 静态成员表示的是静态方法和静态属性,由构造函数提供。
  • 实例成员表示的是实例方法和实例属性,由构造函数创建的对象,也就是实例对象提供。

9、小结

  • 什么是原型?
  • 如何使用原型?
  • 什么是原型继承? => 实例对象默认连接到原型中,可以继承原型的方法和属性,也可以自己给原型赋值
  • 如何实现? => 混合式继承

默默
252 声望5 粉丝