图解原型
function Person() {//TODO}
var p = new Person();
代码执行之前要经历一个预解析的过程。function Person(){}
是函数声明,p
也是声明(p 没有画出来),声明在预解析的时候完成。
- 内存情况
所以,在代码开始运行时,构造函数 Person
在内存中已经存在了,所以代码运行起来第一句话是要执行var p = new Person();
程序开始执行
- 执行 new 创建对象
- 执行构造函数
Person
初始化对象(给对象添加属性) - 内存情况
- 赋值给变量 p
- 针对构造函数来说,Person类型对象是构造函数的实例对象
- 针对构造函数来说,神秘对象是构造函数的原型属性
- 针对Person类型对象来说,神秘对象是Person类型对象的原型对象
/* 接上面的代码 */
Person.prototype.good = function() {console.log("好");}
p.good(); //好
p
表示的对象默认连接到Person.prototype
,Person
类型对象中是不存在good
方法的,但是p
也可以访问到good
方法,由此可见,当当前对象中不存在某属性或方法时,会去神秘对象中去查找。所以可以说,当前对象(Person类型对象
)继承自神秘对象;也可以说,当前的实例对象,继承自其原型对象,这就是原型继承
。
- 原型继承
为什么使用原型
-
为什么属性一般不放在原型上
- 属性表示对象的特征,是一种对象特有的东西,对象不一样,属性也应该不一样。但如果放到原型上,那么就会被所有对象共享
-
为什么方法可以放在原型上
- 属性是对象特有的,但是这个对象的行为应该是一样的。比如人和人是不一样的,但是人都会走路,吃饭,这就是行为,每个人都是一样的,所以可以将其放在原型中复用
-
如何修改原型
1、 利用对象的动态特性Student.prototype.sleep = function(){}
2 、利用直接替换
/* 构造函数.prototype.xxxx = vvvv */ /* 直接将原型进行了替换 */ Student.prototype = { sleep: function(){} study: function(){} }
- 第一种方式与第二种方式最大的不同是,第二种方式又创建出了一个对象,将原有的原型对象进行了替换,所以现在内存中又两个对象;第一种做法是直接在原来的对象上添加属性
分析以下题目
function Person() {}
Person.prototype.func = function () {
console.log("11111");
};
var p1 = new Person();
Person.prototype = {
func: function () {
console.log("2222");
}
};
var p2 = new Person();
p1.func();
p2.func();
- 预解析构造函数
- 构造函数原型属性赋值
- var p1 = new Person();
- 原型属性重新赋值,首先执行等号右边的语句,也就是在内存中创建了一个对象
- var p2 = new Person();
- 此时构造函数的原型属性已经指向了匿名对象,所以新创建的
Person
类型的对象的原型对象也指向匿名对象 - 从图可以得知,
p1.func()
执行结果是1111
;p2.func()
执行结果是2222
总结:只要对象创建出来了,即使原型属性被重新赋值,那么也不会影响已经创建好的对象的功能
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。