原型的类别
· 显示原型: prototype,是每个函数function;
· 隐式原型: _proto_, 是每个对象具有的属性;
1. 函数的prototype属性:
(1) 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
打印console.log(typeof Date.prototype, Date.prototype);
(2) 定义一个新函数:
function fun () { }
console.log(fun.prototype) // 默认指向一个Object空对象
可以看到Date函数里添加了已经定义好的很多属性,而我们自己新建的函数里只有一个prototype属性。
(2)原型对象中有一个constructor,他指向函数对象
* 检查方法:
console.log(Date.prototype.constructor) === Date) // true
console.log(Fun.prototype.constructor) === Fun)// true
2. 给原型对象添加属性(一般是方法) --> 实例对象可访问
* 作用:函数的所有实例对象自动拥有原型中的属性(方法)
funstion Fun() {
}
Fun.prototype.test = funstion() { // 添加属性
console.log(' test() ')
};
var fun = new Fun(); // 新建实例对象
fun.test(); // 调用,可以正常输出,添加属性成功
3.
假设函数名是Type,他有一个protype属性,所指向的是Type的原型对象Type Protype,而原型对象的constructor属性又指向Type。也就是说构造函数和原型对象相互引用的关系。
4.
定义构造函数
function Fn() { } // 内部语句:this.prototype = { },
创建函数的时候给函数添加prototype属性,此句代码所产生的栈和堆空间如图:
定义一个函数,实际上是在堆空间内创建了一个Function对象,函数名Fn在栈空间里面地址值为0X123,Function对象的地址值也就是为0X123;Function对象里面有一个prototype属性(引用变量属性),它的值是个地址值为0X234;鉴于上面的内部语句 this.prototype = { } 可以得知,prototype属性其实是指向一个空object对象,至此我们这个函数语句才完成。
(1). 每个函数function都有一个prototype,即显式原型(属性),默认指向一个空的Object对象;
console.log(Fn.prototype);
所以说Fn.prototype最终输出的是个空对象。
(2). 每个实例对象都有一个__proto__,即隐式原型(属性), 在创建对象的时候就加上了
创建实例对象
var fn = new Fn(); // 内部语句:this_proto_= Fn.prototype
console.log(fn._proto_);
定义一个引用类型的fn变量地址值为0X345,在堆空间中产生Fn的实例对象,地址值为0X345;实例对象上的_proto_属性的地址值(this_proto_= Fn.prototype)就是0X234,同时说明_proto_属性也是指向空object对象的。
(3). 对象的隐式原型的值为其对应构造函数的显式原型的值;
console.log(Fn.prototype === fn._proto_); // true
(prototype和__proto__指向的都是地址值)
根据以上几句代码,可以得出console.log(Fn.prototype === fn._proto_)为true。
(4) . 给原型添加方法
Fn.prototype.test = function () {
console.log(' test() ')
}
通过Fn.prototype.找到空object对象,在此对象上添加方法。
通过实例调用原型的方法
fn.test ()
通过fn.找到Fn的实例对象这个堆空间,但是上面没有test()属性,通过对象调用某个方法或者属性,先在本身的属性上面找(Fn的实例对象), 没有的话去原型对象上找;根据隐式原型属性去找(隐式原型的值开始赋得也是显示原型的值0X234)而不是显示原型。