JS原型与原型链

一.普通对象与函数对象

Javascript中,万物皆对象,但分为普通对象和函数对象,Object,Function是JS自带的函数对象。 
下面举例说明:

function f1(){};
console.log(typeof f1);//输出function 函数对象

var f2 = function(){};
console.log(typeof f2);//输出function 函数对象

var f3 = new Function('str','console.log(str)');
console.log(typeof f3);//输出 function 函数对象

var a1 = new f1();
console.log(typeof a1);//输出object 普通对象

var a2 = {};
console.log(typeof a2);//输出object 普通对象

var a3 = new object();
console.log(typeof a3);//输出object 普通对象

二.原型对象

在JavaScript中,每当定义了一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象prototype。普通对象无prototype属性,但是有_ proto_属性 
下面来说一说prototype 和_ proto _ 
prototype:显示原型 
_ proto _:隐式原型 
1.显示原型和隐式原型是什么? 
函数对象具有的一个属性是prototype,称为显示原型,这个属性是一个指针,指向原型对象。原型对象也有一个属性constructor,这个属性包含一个指针,指向原构造函数

如上图,SuperType是一个函数,右侧的方框就是它的原型。

对象都具有的一个属性proto称为隐式原型,对象的隐式原型指向构造该对象的构造函数的显示原型

探究二者之间的关系

隐式原型指向创建这个对象的函数的prototype 
下面来探究一下三种创建对象的方法中隐式原型和显示原型的关系:

1.通过对象字面量来创建一个对象

var person = {
  name = "Tom";
}

通过对象字面量的方式创建的对象,它的隐式原型指向Object.prototype,因为person这个对象是通过new Object()函数所创建出来的 
上面的代码相当于:

var person = new object();
 person.name = "Tom";

2.通过Object.create()方式创建

先介绍一下Object.create()方式 
1.定义: 
Object.create()方法会使用指定 的原型对象及其属性去创建一个新的对象 
2.语法:

Object.create(proto, [ propertiesObject ])

3.参数: 
proto 
一个对象,新创建的对象的原型。 
propertiesObject 
可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)。注意:该参数对象不能是 undefined,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的 
4.返回值: 
返回一个新对象。在指定原型对象上添加新属性后的新对象 
5.抛出异常: 
如果 propertiesObject 参数不是 null 也不是对象,则抛出一个 TypeError 异常 
举例:用Object.create实现类继承

//Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
    console.info("Shape moved.");
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); //call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true

rect.move(1, 1); //Outputs, "Shape moved."

通过这种方法创建的对象的隐式原型指向proto

通过new方式创建

function person(name){
  this.name = name;
}
//创建一个构造函数的实例
var person1 = new person();

构造函数function person 本质是由Function构造函数创建的,它是Function 的一个实例。原型对象本质是由Object构造函数创建的。内置函数Array,Number,等也是由构造函数创建的 
下面来探究person1的隐式原型:

//通过new的方式
person1.__proto__===person.prototype //true
person.prototype.__proto__===Object.prototype //true   person.prototype也是一个对象,它是通过new Object创建得到的
Object.__proto__===Function.prototype //true
//内置函数
Array.__proto__===Function.prototype //true
Array.prototype.__proto__===Object.prototype //tr

Function的proto指向其构造函数Function的prototype;

Object作为一个构造函数,它是一个函数对象,所以他的proto指向Function.prototype;

Function.prototype的proto指向其构造函数Object的prototype;

Object.prototype的prototype指向null(尽头);

经典图片解析: 

其实:原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性)。 
举例:

function f1(){};
 console.log(f1.prototype) //f1{}
 console.log(typeof f1. prototype) //Object
 console.log(typeof Function.prototype) // Function,这个特殊
 console.log(typeof Object.prototype) // Object
 console.log(typeof Function.prototype.prototype) //undefined

从这句console.log(f1.prototype) //f1 {} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype 
原型对象是用来做什么的呢?主要作用是用于继承。举个例子:

var person = function(name){
 this.name = name;
}
person.prototype.getname = function(){
  return this.name;
}
var zjh = new person('zhangjiaahao');
zjh.getName();//zhangjiaohao

从这个例子可以看出,通过给person.prototype设置了一个函数对象的属性,那有person实例(例中:zjh)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。

三.原型链

JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做proto的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例: 
console.log(zjh.proto === person.prototype) //true

同样,person.prototype对象也有proto属性,它指向创建它的函数对象(Object)的prototype

console.log(person.prototype.proto === Object.prototype) //true

继续,Object.prototype对象也有proto属性,但它比较特殊,为null

console.log(Object.prototype.proto) //null

我们把这个有proto串起来的直到Object.prototype.proto为null的链叫做原型链

 

posted @ 2018-09-17 16:38  一抹夏忧☆  阅读(179)  评论(0编辑  收藏  举报