首先,原型是一个对象。并且全部的对象都有一个原型(有一种例外:当把对象的原型设为null时),而且任何对象均可以成为一个原型。javascript
当咱们定义一个对象时 var a = new Object();
默认的原型在原型链的顶端。java
原型最大的好处体如今它的 共享
的特性。全部原型对象的实例对象共享它所包含的属性和方法。因此咱们经常使用利用原型来建立对象,也就是 原型模式
。数组
原型模式
是一种用来建立多个实例对象的方法,咱们经常把它和 构造函数
结合起来用来建立特定类型的对象。函数
咱们建立的每个函数都有一个 prototype
属性,这个属性是一个指针,指向一个对象。这个对象的用途是包含能够由特定类型的全部实例共享的属性和方法。这个对象就是实际上经过调用构造函数而建立的 实例对象
的原型对象。看代码:this
// 构造函数 function Person(){}; Person.prototype.name = "darko"; Person.prototype.age = 21; Person.prototype.sayName = function(){ alert(this.name); } var person1 = new Person(); person1.sayName(); // "darko" var person2 = new Person(); person2.sayName(); // "darko"
咱们将全部的属性和sayName()
方法添加到了构造函数Person
的prototype
属性中,构造函数成了空函数。可是即使如此,咱们也能够经过调用构造函数来建立新对象,并且新对象还会具备相同的属性和方法。spa
实例对象就是经过构造函数创造的,默认拥有一个constructor
属性指向其构造函数。prototype
原型对象就是构造函数的属性prototype
指向的那个对象,同时也是基于构造函数生成的实例对象的原型对象。在默认状况下,全部的原型对象都会自动得到一个constructor
属性,这个属性是一个指针,指向其构造函数。指针
实例对象能够访问原型对象上的属性和方法。在实例对象的内部有一个属性(内部属性)[[Prototype]]
指向其原型对象。有一种非标准方法__proto__
访问[[Prototype]]
。code
在上面的例子中person1
和person2
就是实例对象,构造函数为Person
,原型对象为Person.prototype
。对象
来,看个栗子(仍是上面那段代码):
alert(person1.constructor === Person); // true alert(Person.prototype.constructor === Person); // true alerta(person1.__proto__ === Person.prototype); // true
来看个图你就什么都懂了:
prototype
是函数的一个默认属性,只有函数对象才有
Object.getPrototypeOf()
方法用来返回实例对象内部属性[[prototype]]
的值。这是ES5中定义的用来获取原型对象的标准方法。
__proto__
属性是获取原型对象的非标准方法(IE不支持)
看个栗子(仍是上面那段代码):
alert(Object.getPrototypeOf(person1) === Person.prototype); // true alert(Object.getPrototypeOf(person1).name); // "darko" alert(person1.__proto__ === Person.prototype); // true alert(person1.__proto__.name); // "darko"
每次查找对象的每一个属性,都是一次搜索。搜索从实例对象自己开始,若是在实例对象中找到,中止查找,返回值。若是没有则继续搜索实例对象指向的原型对象。
若实例对象中属性和其指向的原型对象的属性重名,实例对象中的属性屏蔽原型对象中的那个属性。
举个栗子:
function Person(){}; Person.prototype.name = "darko"; Person.prototype.age = 21; Person.prototype.sayName = function(){ alert(this.name); } var person1 = new Person(); var person2 = new Person(); person1.name = "leon"; person1.sayName(); // "leon",来自实例 person2.sayName() // "darko",来自原型 delete person1.name; person1.sayName(); // "darko",来自原型
能够利用hasOwnProperty()
方法判断一个属性是位于实例中,仍是原型中。只有在属性来自实例中时,才会返回true
。一般和in
操做符配合使用。
// 接上 alert("name" in person1); // true alert(person1.hasOwnProperty("name")); // false
全部的原生引用类型都在其原构造函数的原型上定义了方法,例如,Array.prototype.sort()
方法,正是因为原型的共享特性,咱们定义的数组才可使用sort()
方法等一系列的方法。
举个栗子:
var num = [1, 5, 3, 7, 9]; num.sort(); // 1,3,5,7,9 alert(num.constructor === Array); // true alert(num.__proto__ === Array.prototype); // true alert(num.__proto__.__proto__ === Object.prototype); //true
数组对象num
自己就是构造器Array
的实例对象,而Array
的prototype
属性指向的对象上定义了sort()
方法,因此新定义了num
对象通过搜索找到了sort()
方法,并调用了方法。
因为在原型中查找值的过程是一次搜索,因此对原型对象的任何修改都能当即从实例上反应出来。
举个栗子:
function Person(){}; var firend = new Person(); // 修改原型 Person.prototype.sayHi = function(){ alert("Hi"); } firend.sayHi(); // "Hi"
可是若将原型重写,来看看有什么不一样:
function Person(){}; Person.prototype.name = "darko"; var firend = new Person(); // 重写了原型对象 Person.prototype = { constructor: Person, // 注意:重写原型对象,因此此时的constructor属性变成了新对象的构造函数,默认为Object构造函数,应该将其设置回适当的值 sayHi: function(){ alert("Hi"); } } alert(friend.name); // "darko" firend.sayHi(); // error
这说明,重写原型对象切断了现有原型和任何以前已经存在的实例对象之间的联系,它们引用的还是最初的原型。
若是你以为我写的还能够,点一下推荐吧。