经过面试的挫折之后,继续深入学习~~
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、小结
- 什么是原型?
- 如何使用原型?
- 什么是原型继承? => 实例对象默认连接到原型中,可以继承原型的方法和属性,也可以自己给原型赋值
- 如何实现? => 混合式继承
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。