一、理解
1、什么是原型?
在JavaScript中原型是一个prototype对象,用于表示类型之间的关系。
2、什么是原型链?
原型链是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。
Object ==> 构造函数1 ==> 构造函数2
就和css中的继承一样,如果自身没有定义就会继承父元素的样式。
二、__proto__
与 prototype
1)、prototype(函数的原型对象):函数才有prototype,而且所有函数必有prototype。prototype是一个对象,指向了当前构造函数的引用地址呢。
2)、 __proto__
(对象的原型):对象才有__proto__
,而且所有对象必有__proto__
属性(这里的对象除了我们理解的狭义对象,也包括了函数、数组等对象)。当用构造函数实例化(new)一个对象时,会将新对象的__proto__
属性,指上构造函数的prototype。
来看个案例:
function Person(){
// do something
}
var zhangsan = new Person();
console.log(zhangsan.__proto__ == Person.prototype); // true
【解释】上例中,我们使用函数Person,new出了一个对象zhangsan。 那么对象zhangsan(类似Java对象)的__proto__
就等于函数Person(类似Java类)的prototype。
三、原型的作用是什么?
1.数据共享 节约内存内存空间
2.实现继承
下面我将举例说明为什么要使用原型:
function Person(name) {
this.name=name;
this.eat=function () {
console.log(this.name+"吃东西");
}
this.sleep=function () {
console.log(this.name+"睡觉");
}
}
var p1=new Person("小明");
p1.eat(); //小明吃东西
p1.sleep(); //小明睡觉
var p2=new Person("小利");
p2.eat(); //小利吃东西
p2.sleep(); //小利睡觉
console.dir(p1); //dir()打印结构
console.dir(p2);
四、原型链的四大准则
① 通过构造函数,new出的对象,新对象的__proto__
指向构造函数的prototype
② 所有函数的__proto__
指上Function()的prototype
③ 非构造函数new出的对象( {} new Object() 对象的prototype)的__proto__
指向Object的prototype
④ Object的prototype的__proto__
指向null
五、prototype对象
js中函数具有两重性:首先,函数可以划分作用域,一个函数就是一个执行环境(这也是个大话题,本文暂不提)。其次,一个函数也是一个对象,属Function类型。既然是对象,就可以有属性和方法,而原型(prototype)就是函数的一个属性。
下面的代码定义了一个函数:
function Daddy(name){
this.name = name
}
看上去只是添加了一个属性,但它背地里还偷偷地做了点坏事,我现在把它揭露出来,上面代码和下面代码的执行结果可以认为是一致的:
function Daddy(name){
this.name = name
}
Daddy.prototype = {};
Daddy.prototype.constructor = Daddy;
我们来看看它到底偷偷做了些啥:
- 在定义一个函数后,立马为这个函数添加一个prototype属性。
- prototype属性被赋予一个Object对象,现在prototype也成为对象了。
- 为prototype对象添加constructor属性,并指向函数Daddy本身。
所谓的”原型”、”原型对象”这些名词,说的就是此刻的prototype对象。
六、prototype和__proto__的区别是什么?
七、通过new关键字理解prototype和__proto__
下面将以var fun=new Function();为例简单的了解下new的过程中究竟干了个嘛?
new Function()={
var fun={};
fun.__proto__=Function.prototype;
var result=Function.call(fun);
return typeof result==='Function'?result:fun;
}
不难看出其实在new对象时不是简单的返回一个对象,中间经历了核心的三步:
1.首先就是创建一个同名的空的fun对象;
2.紧接着就是把Function上的prototype属性赋给fun对象的__proto__属性(这里不知道这个是什么没有关系就知道进行了这么一步,后面讲解prototype,__proto__时会详细介绍);
3.使用fun替换Function的上下文context