快速了解面向对象编程的一些概念

1.原型 prototype

JavaScript的每个对象都继承另一个对象(“原型”(prototype)对象)。我们要记住,每一个对象(null除外)都有原型对象,无论是通过那种方式创建的对象。

1).如果对象是通过对象直接量创建的。

var o={};

那么我们可以通过Object.prototype获得对原型对象的引用

2).如果对象是通过关键字new和构造函数创建的话。

对象的原型对象就是构造函数的prototype值

function Animal(){

}
var pig=new Animal();
pig对象的原型对象就是Animal.prototype

3).如果对象是通过new Object()创建的,那么原型对象就是Object.prototype

总结:当调用构造函数创建了一个新实例后,该实例的内部将包含一个指针(内部属性prototype),指向构造函数的原型对象。我们始终要明确,这个连接是存在于实例对象与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

2.constructor属性

默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法。prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。

function P() {}
P.prototype.constructor === P // true

var p = new P();
p.constructor // function P() {}
p.constructor === P.prototype.constructor // true
p.hasOwnProperty('constructor') // false

constructor属性的作用,是分辨原型对象到底属于哪个构造函数。

由于constructor属性是一种原型对象与构造函数的关联关系,所以修改原型对象的时候,务必要小心。

实例

function A() {}
var a = new A();
a instanceof A // true

function B() {}
A.prototype = B.prototype;
a instanceof A // false

上面代码中,a是A的实例。修改了A.prototype以后,constructor属性的指向就变了,导致instanceof运算符失真。

所以,修改原型对象时,一般要同时校正constructor属性的指向。

实例

Cat.prototype = new Animal();//赋予一个新值,它相当于完全删除了prototype 对象原先的值,包括原型对象所指的构造函数

Cat.prototype.constructor = Cat;//任何一个prototype对象都有一个constructor属性,指向它的构造函数,将原型对象的构造函数改回Cat。

如果替换了prototype对象,

  o.prototype = {};

那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

  o.prototype.constructor = o;

3.原型链

var arr=new Array();

新创建了一个arr对象,它的原型对象是Array.prototype,那么Array.prototype的原型对象是什么了?答案是Object.prototype,即Object构造函数的prototype属性指向的那个对象,那么Object.prototype有原型对象吗?有,是null(Object.getPrototypeOf(Object.prototype)结果返回none),原型追溯到这里也就终止了。

所以所有对象如果一层层地往上上追溯,所有对象的原型最终都可以上溯到Object.prototype,这样就形成了一条原型链了。

4.继承

对象的属性和方法,有可能是定义在自身,也有可能是从定义在它的原型对象那继承而来的。为了更好理解继承,我们需要了解属性访问的细节。

假设我们要查询对象o的属性x,如果o中没有x,那么将会继续在o的原型对象中查询属性x,如果这个原型对象也没有x,那么就继续在这个原型对象的原型中找,直到找到x或者找到原型对象是null为止。我们可以看到,在找属性x时,对象的原型属性构成了一个链,通过这个链就可以实现属性的继承。

实例

var o={};
o.x=1;//自定义属性x
var p=inherit(o);//p继承o和Object.prototype
p.y=2;//自定义一个属性y
var q=inherit(p);//q继承p,o和Object.prototype
p.z=3;//自定义一个属性z
var s=q.toString();//q.toString()继承自Object.prototype
q.x+q.y//结果为3,x和y分别继承o和p

只有在查询属性时,才会体会到继承的存在。如果o中已经有x属性了,那么这个属性就不是继承而来的,无论它的原型对象是不是也有x属性,如果原型对象也有x属性,那么o中的x属性就相当于重写了x(对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。,否则就是自定义属性了。

原文地址:https://www.cnblogs.com/YeChing/p/6284589.html