1. 定义:原型是function/函数对象(包括构造函数)的一个属性,它定义了函数构造出的对象的公共祖先。通过该函数构造出的对象,可以继承该原型的属性和方法。原型也是对象。
对该定义的解释:
所有的function对象都有一个系统自带的prototype
属性,翻译过来即“原型”。有这么一个函数function Person(){}
,function对象Person的prototype
属性(即原型)也是一个对象,存在Person.prototype = {...}
,我们可以把Person.prototype
理解为是Person对象的祖先对象(唯一),此后所有Person的实例对象都会继承Person.prototype
祖先对象的属性和方法。
范例:
Person.prototype.name = "haha";//定义Person的祖先对象中的name属性
Person.prototype.say = function(){//定义Person的祖先对象中的say方法
console.log("aha");
}
function Person(){}
var person = new Person();
var person1 = new Person();
function对象Person的两个实例对象都为空(没有自己的属性和方法) 但都继承了来自祖先的name属性和say方法
function对象Person的实例对象可以同时有自己的属性和方法,也有继承来的属性和方法
Person.prototype.LastName = "Liu";
Person.prototype.say = function(){
console.log("aha");
}
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person("zhuzhu",23,"男");
可以看到function对象Person的实例对象不为空 有自己的属性 同时也有继承来的属性和方法
使用hasOwnProperty
方法可以判断该属性或方法是否是只存在于实例对象而不存在于原型对象上
console.log(person.hasOwnProperty("name")); // true
console.log(person.hasOwnProperty("say ")); // false
2.原型的应用
2.1利用原型的特点和概念,可以提取共有属性
源代码:
function Car(color,owner){
this.owner = owner;
this.carName = "BMW";
this.height = 1400;
this.lang = 4900;
this.color = color;
}
var car = new Car('red','ls');
每次function对象Car需要创建新的实例对象都会执行下面三行相同的代码
this.carName = "BMW";
this.height = 1400;
this.lang = 4900;
这会造成代码冗余 ,我们可以用原型提取出来,通过继承祖先的属性和方法让每一个创建的Car对象都拥有共有的属性
改进代码:
Car.prototype.carName = "BMW";
Car.prototype.height = 1400;
Car.prototype.lang = 4900;
function Car(color,owner){
this.owner = owner;
this.color = color;
}
var car = new Car('red','ls');
2.2原型的增删改查
Car.prototype.carName = "BMW";
Car.prototype.height = 1400;
Car.prototype.lang = 4900;
function Car(color,owner){
this.owner = owner;
this.color = color;
}
var car = new Car('red','ls');
增
不能通过创建出来的car对象新增原型的属性方法,因为prototype属性是function对象的属性,不是创建出来的car对象的属性
可以通过function对象Car调用prototype属性新增原型属性
删
创建的car对象可以通过delete关键字删除自己的属性
但创建的car对象不可以通过关键字delete删除原型的属性
删除后 返回true(返回true是因为系统认为删除一个不存在的属性也ok)
但原型属性并没有被删去
function对象的prototype属性可以通过delete关键字实现原型属性的删除
查
不能通过创建出来的car对象查看原型的属性方法,因为prototype属性是function对象的属性,不是创建出来的car对象的属性
用function对象可以查看原型属性方法
改
创建的car对象都不能查看原型,自然是更改不了原型属性方法
function对象可以通过prototype属性更改原型属性方法
3.对象查看对象的构造函数【隐式属性constructor】
function Car(){}
var car = new Car();
浅粉色字体表示系统隐式地自动创建的属性方法
constructor属性可以被修改
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
Car.prototype={
constructor : Person
}
function Car(){}
var car = new Car();
4.对象查看原型 【隐式属性__proto__(前后各两个杠)】
Car.prototype.name = "kkk"
function Car(){}
var car = new Car();
在代码中我们只给构造函数的原型添加了name属性,由此可知 对象的隐式属性__proto__ 指向的是 其构造函数的原型
相当于
Car.prototype.name = "kkk"
function Car(){
//var this = {
// __proto__:Car.prototype
//}
}
var car = new Car();
代码中隐去的过程只会在Person对象被创建时隐式地发生
__proto__属性指向的原型可以被更改
在原有代码基础上添加下面obj对象
var obj = {
name:"ff"
}
在控制台对对象的__proto__属性进行更改,__proto__属性被改变,对象原型也相应的改变
问题1:代码如下 创建的person对象的name属性是什么?
Person.prototype.name = "Liu";
function Person(){}
var person = new Person();
Person.prototype.name = "lei";
这是在原有的原型基础上把name属性改了
换一种写法呢?此时创建的person对象的name属性是什么?
Person.prototype.name = "Liu";
function Person(){}
var person = new Person();
Person.prototype = {
name:"lei"
}
这是直接把原型给改了,换了个原型对象,为什么呢?
举个简单的例子 便于理解
//引用值obj指向对象{name:"a"}
var obj = {name : "a"};
//引用值obj1指向了引用值obj指向的对象{name:"a"}
var obj1 = obj;
//obj改为指向对象{name:"b"} 而原有对象{name:"a"}依旧存在,obj1仍指向原有对象
obj = {name : "b"} ;
同样的 回到原问题
Person.prototype.name = "Liu";
function Person(){}
var person = new Person();
Person.prototype = {
name:"lei"
}
在创建一个person对象的时候,发生以下过程
function Person(){
//var this = {__proto__ : Person.prototype}
}
person对象的__proto__
和其构造函数Person的prototype属性指向同一空间对象
Person.prototype = {
...
}
Person.prototype指向另一空间对象,而__proto__仍指向原来的对象
person.name是从person.__proto__属性中取值,而__proto__仍指向原来的对象,故name属性的值仍为"Liu"
问题2:代码如下 创建的person对象的name属性是什么?
Person.prototype.name = "Liu";
function Person(){}
Person.prototype = {
name:"lei"
}
var person = new Person();
代码的顺序非常重要 会影响程序执行的结果
只有在创建对象的时候,才会在对象中发生var this = {__proto__ : Person.prototype}
这一过程,而在创建对象之前,Person.prototype属性已被改变,指向对象{name:“lei”},故创建的person对象的__proto__属性也指向同一对象{name:“lei”}