1. __ proto __
众所周知,JS中万物皆对象,所以每一个数据都会有一个__ proto __ 属性,这个属性叫隐式原型
。
一个对象(obj)的隐式原型( __ proto __ )
指向构造该对象的构造函数(Object())的原型属性(Object.prototype)
。这样做的原因是为了保证实例(obj)能够访问到在构造函数的原型属性(Object.prototype)中定义的属性和方法。
2.prototype
函数是一个特殊的对象,除了和其他对象一样有 __ proto __ 属性之外,还有自己特有的属性(prototype
),这个属性被描述成指针
。它指向的是一个对象类型的数据,这个对象的用途就是包含所有将来使用该函数构造出来的可被共享的属性和方法(我们把这个对象称之为原型对象)。
原型对象也有一个属性,叫做constructor
,这个属性包含一个指针,指回了原函数。类似于arguments.callee,但是arguments只能在函数内部获得,而函数原型对象内的constructor属性,可以在任何能访问到这个函数的位置使用。
3.构造函数、原型、实例之间的关系
- 构造函数
Fn身上
有属性prototype
为原型对象,原型对象内有constructor
属性指向当前prototype所在
的构造函数Fn; - 在
new执行
构造函数Fn时,创造了一个实例对象
f,实例对象f的__proto__
指向构造函数Fn的原型prototype
; - 因为实例对象
f的__proto__
指向构造函数Fn的原型prototype
,所以实例对象f
可以间接访问到Fn原型prototype的方法
。
4.实例和原型关系检测
isPrototypeOf()函数
,用于检测两个对象之间似乎否存在原型关系,使用方法如下:
// 查看 Fn 的 prototype 对象,是否是 f 原型
Fn.prototype.isPrototypeOf(f);
instanceof运算符
,用于检测某实例是否来自于某构造函数,使用方法如下:
// 查看 f 对象是否是构造函数 Fn 的实例
console.log(f instanceof Fn);
// 查看 f 对象是否是构造函数 Fn 的实例
console.log(f instanceof Object);
两种使用,如果是返回ture,如果不是返回false;
注意:instanceof运算符右侧为构造函数,并且js中所有原型都来自Object构造函数。
function Fn(){}
function Fun(){}
var f = new Fn();
console.log( f.__proto__ === Fn.prototype ); // t
console.log( Fn.prototype.isPrototypeOf(f) ); // t
console.log( Fun.prototype.isPrototypeOf(f) ); // f
console.log( Object.prototype.isPrototypeOf(f) ); // t
console.log( f instanceof Fn ); // t
console.log( f instanceof Fun ); // f
console.log( f instanceof Object ); // t
5. JS解析器访问属性顺序
当访问实例 f
的属性或方法时,会先在当前实例对象 f
中查找,如果没有,则沿着__proto__
继续向上寻找,如果找到最顶头的Object
还是找不到,则会抛出undefined
。如果在实例中找到
,或某层原型中找到
,就会读取并使用
,同时停止向上
找寻。
由此可见,解析器的解析顺序遵循就近原则
,如果在最近的位置发现属性存在,便不会继续向上找寻。
6. 原型的应用
(1)简单应用:
function Fn(){
this.test= "hello";
}
Fn.prototype.show = function(){
console.log(this.test);
}
var f = new Fn();
console.log(f);
f.show();
(2)数组去重:
Array.prototype.noRepeat = function(){
var m = [];
for(var i=0;i<this.length;i++){
if(m.indexOf(this[i]) == -1){
m.push(this[i]);
}
}
return m;
}
var arr = [3,4,5,6,7,6,5,4,3,2,1];
var res = arr.noRepeat();
console.log(res);
var arr1 = ["a","b","c","b","a"];
var res1 = arr1.noRepeat();
console.log(res1);
- 原型的继承
示例①
function Parent(){
}
Parent.prototype.show = function(){
console.log("哈哈哈");
}
function Child(){
}
for(var i in Parent.prototype){
Child.prototype[i] = Parent.prototype[i];
}
Child.prototype.show = function(){
console.log("hello");
}
var p = new Parent();
p.show();
console.log(p.name);
var c = new Child();
c.show();
console.log(c.name);
示例②
function Parent(){
this.name = "hello world";
}
Parent.prototype.show = function(){
console.log("哈哈哈show方法");
}
function Child(){
}
var p = new Parent();
console.log(p)
var c = new Child();
console.log(c);