原型是什么东西?
只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成为原型链。 原型链继承就是利用就是修改原型链结构( 增加、删除、修改节点中的成员 ), 从而让实例对象可以使用整个原型链中的所有成员( 属性和方法 )。
普通对象与函数对象
var o1 = {};
var o2 = new Object();
var o3 = new f1();
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function() 的方式进行创建的。Function Object 也都是通过 New Function() 创建的。
原型对象
原型对象,顾名思义,它就是一个普通对象。原型对象就是 Person.prototype ;
每个函数对象都有一个 prototype 属性,这个属性指向函数的原型对象。
每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性。
在默认情况下,所有的原型对象都会自动获得一个 constructor (构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)。
原型对象(Person.prototype)是 构造函数(Person)的一个实例。
Person.prototype.constructor == Person
var abc = function(){
this.name="小明";
}
// 函数对象
abc.prototype.say=function(){
alert(this.name);
}
var a = new abc();
a.say();
//小明
// 这么做的好处是不会额外产生内存,
// 所有实例化后的对象都会从原型上继承这个方法
构造函数(constructor)
JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做 __proto__ 的内置属性,用于指向创建它的构造函数的原型对象。
对象 person1 有一个 __proto__ 属性,创建它的构造函数是 Person ,构造函数的原型对象是 Person.prototype ,所以:person1.__proto__ == Person.prototype;
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');
// person1 和 person2 都是 Person 的实例。
// 实例的构造函数属性(constructor)指向构造函数。
//构造函数
function Foo(name,age){
this.name = name
this.age = age
this.class = 'class-1'
}
//实例化
var f1 = new Foo('Jon',20);
var f2 = new Foo('daming',22);
f1.constructor == Foo; //true
f1.__proto__ == Foo.prototype //true
//__proto__用于指向创建它的构造函数的原型对象。
Foo.prototype.constructor == Foo; //true
//实例的构造函数属性(constructor)指向构造函数。`
function Person(){}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype) //true
console.log(Object.prototype.__proto__) //null
Person.__proto__ == Function.prototype; //true
console.log(Function.prototype)// function(){} (空函数)
var num = new Array()
console.log(num.__proto__ == Array.prototype) // true
console.log( Array.prototype.__proto__ == Object.prototype) // true
console.log(Array.prototype) // [] (空数组)
console.log(Object.prototype.__proto__) //null
console.log(Array.__proto__ == Function.prototype)// true
如上图所展示的,原型对象指向构造函数的指针是 constructor ,构造函数的 prototype 指向原型对象,构造函数通过 new 操作符来创建一个实例 , 实例又可以通过内部指针 __proto__ 指向原型对象。
__proto__ 连接的这一条原型对象就构成了原型链。
Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
person1.constructor == Person;
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
实例(tidy)和 原型对象(dog.prototype)存在一个连接。不过,要明确的真正重要的一点就是,这个连接存在于实例(tidy)与构造函数的原型对象(dog.prototype)之间,而不是存在于实例(tidy)与构造函数(dog)之间。