原型及原型链是JavaScript中的重难点。本文是作者对JS原型与原型链相关内容的学习笔记,希望对各位读者大人会有所帮助。若有疑问或不正之处,欢迎提出指正和讨论。
1、对象
众所周知,在JavaScript中,万物皆对象。不过,对象分两类:普通对象和函数对象。Object和Function是JS自带的函数对象。
var a1 = {}
var a2 = new Object();
var f1 = function(){};
var f2 = new Function('sayhi', 'alert("hello world!")')
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof a); //object
console.log(typeof f); //function
从以上示例,可以看出,凡是通过new Function()创建的对象都是函数对象,其他都是普通对象。
2、构造函数
function Person(name){
this.name = name;
this.sayName = function(){ alert(this.name) }
}
var per1 = new Person("lin");
var per2 = new Person("fang");
console.log( per1.constructor == Person ); //true
console.log( per2.constructor == Person ); //true
从以上示例,可以看到per1和per2都是Person(构造函数)的实例,实例存在一个constructor属性,该属性指向Person,即:实例的constructor属性指向其构造函数。
3、原型对象
在JavaScript中,定义一个对象时,对象都会包含一些默认属性。每个对象都有__proto__属性,只有函数对象才存在prototype属性,该属性指向函数的原型对象。
原型对象,顾名思义,就是普通对象。
Person.prototype = {
name: 'lin',
sayName: function() {
alert(this.name);
}
}
在以上示例中,可以看到,我们给Person.prototype添加了两个属性:name、sayName,其实还存在一个默认属性:constructor。
在默认情况下,所有的原型对象都存在一个默认属性constructor,该属性指向prototype属性所在的函数;即:Person.prototype.constructor == Person。
在此我们得出一个结构:原型对象( Person.prototype )是构造函数( Person )的一个实例对象。
实例对象、原型对象、构造函数的关系如下:
4、_proto_
很多浏览器都给每个对象提供了__proto__内置属性,该属性就是该对象的[[ prototype ]],用于指向创建它的构造函数的原型对象。
即per1.__proto_ _== Person.prototype;
由此我们得到如下关系:::
Person.prototype.constructor == Person;
per1.__proto__ == Person.prototype;
per1.constructor == Person;
在此我们要明确一点:::此关系存在于实例(per1)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(per1)与构造函数(Person)之间。
per1.constructor.prototype = Person.__proto__
5、构造器
众所周知,在JavaScript中,新对象是通过new操作符后跟一个构造函数来创建的。
如:var obj = {};等同于var obj = new Object();
6、函数对象
所有函数对象的__proto__属性都指向了Function.prototype,它是一个空函数(empty function)。
JavaScript中有12个内置构造器/对象(Number、Array、Boolean、String、Date、Object、Function、RegExp、Error及Global、Arguments、Math、JSON),其中Global无法直接访问,Arguments只在函数调用时由JS引擎创建,Math和JSON以对象形式存在,无需new。它们的__proto__就是Object.prototype。
Array.__proto__ ===
Function.prototype
// true
Array.constructor ==
Function
//true
Math.__proto__ ===
Object.prototype
// true
Math.constructor == Object
//true
Object.__proto__ ===
Function.prototype
// true
Object.constructor ==
Function
// true
Function.__proto__ ===
Function.prototype
// true
Function.constructor ==
Function
//true
由此可见,所有的构造器都来自Function.prototypre,甚至包括Object和Function自身;所有的构造器都继承了Function.prototype的属性和方法。如:call、apply等
Function.prototype.__proto__ === Object.prototype //true
Object.prototype.__proto__ === null //true
这真的是”无中生有“啊。
Function.prototype是唯一一个type xxx.prototype为function的prototype,其他构造器都是一个对象。
console.log(
typeof
Function.prototype)
// function
console.log(
typeof
Object.prototype)
// object
console.log(
typeof
Array.prototype)
// object
7、总结
(1)实例的constructor属性指向其构造函数;
(2)每个对象都有__proto__属性,该属性指向函数的原型对象(而不是构造函数);
a、普通对象的__proto__指向了这个对象(this)的构造函数的prototype
b、函数对象的__proto__全部指向了Function的prototype
(3)原型链的形成靠的是__proto__而不是prototype;
本文为JS原型链学习笔记。
如有不妥之处,敬请斧正。