一、原型与原型链
1.1 显示原型与隐式原型
1、显示原型
1) 每个函数都有一个prototype属性,即显示原型。它默认指向一个Object空实例对象,即原型对象。
但是Objct函数除外。
2) 函数的prototype属性:在定义函数时自动添加的,默认指向一个Object空实例对象。
function Fn(){
//内部代码:this.prototype={}
}
2、隐式原型
1) 每个对象都有一个"__proto__"属性,即隐式原型,它默认指向构造函数"prototype"属性指向的原型对象。
2) 对象的__proto__属性:在创建对象时自动添加。默认指向构造函数的prototype属性指向的值。
var s=new Fn();
//内部代码 : s.__proto__=Fn.prototype;
3、实例对象隐式原型的值等于构造函数显示原型的值。他们都指向原型对象。
>>>>>> 每个函数都有一个prototype属性,即原型属性。它默认指向一个Object空实例对象,即原型对象。
function Person(){
}
Person.prototype.a="abc"
//每个函数都有一个prototype属性,它默认指向一个Objct空对象
console.log(Person.prototype)
>>>>>> 每个对象都有一个__proto__属性,即隐式原型。它默认指向构造函数显示原型指向的原型对象。
function Person(){
this.age=12
}
var ss=new Person();
console.log(ss.__proto__);
console.log(ss.__proto__==Person.prototype);//true
>>>>>> 实例对象隐式原型属性的值等于构造函数显示原型的值,它们都指向原型对象
function Person(){
}
//1.每个函数都有prototype属性,即显示原型属性
console.log(Person.prototype)
//2.每个实例对象都有一个—__proto__属性,即隐式原型属性
var o1=new Person();
console.log(o1.__proto__)
//3.实例对象的隐式原型的值等于构造函数的显示原型的值。他们都指向原型对象
console.log(Person.prototype===o1.__proto__)
>>>>>> 函数的显示原型与对象的隐式原型创建原理
//函数的prototype属性:在函数加载时自动添加
function Person(){
//内部代码: this.prototype={};
}
//对象的__proto__属性:在创建对象时自动添加
var p=new Person(); // 内部代码: p.__proto__=Person.prototype
1.2 原型对象
1、函数与原型对象内部互相引用。
每个函数都自带一个prototype属性,即显示原型。它默认指向一个Object空对象,即原型对象。
原型对象中也默认有一个constructor属性,它默认指向该函数。
2、所有函数的原型对象默认都是Object实例。
但是Object函数的原型对象不是Object实例。
,
>>>>>> 原型对象中默认有一个constructor属性,它默认指向该函数。
function Person(){
}
//原型对象
console.log(Person.prototype)
console.log(Person.prototype.constructor === Person)
>>>>>> 函数与原型对象相互引用
案例
function Person(){
this.sayName=function(){
console.log("123")
}
}
//每个函数都有一个prototype属性,它默认指向一个Objct空对象
console.log(Person.prototype)
//原型对象中有一个constructor属性指向该函数
console.log(Person.prototype.constructor)
console.log(Person.prototype.constructor===Person) //true
>>>>>> 所有函数的原型对象默认都是Object实例,但是Object函数的原型对象不是Object实例
function Person(){
this.age=12
}
console.log(Person.prototype instanceof Object); //true
console.log(Function.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
二、原型链
2.1 原型链
1、原型链实质上就是隐式原型链。它的作用就是查找对象的属性。
访问一个对象的属性时,首先在自身作用域中查找。
如果没有,就会沿着隐式原型这条链("__proto__")向上查找,找到就返回。
如果没找到就返回undefined。
2、原型链只能用于查找对象的属性。当设置对象的属性时,不会查找原型链。
3、JS通过原型链实现继承。所有实例都可以访问原型对象的属性和方法。
4、Object函数的原型对象(Object.prototype)
1) 它位于原型链的最顶端。
原因: Object.prototype.__proto__ =null.
2) Object函数的原型对象有许多内置方法,比如 toString()、hasOwnProperty()。
3) 所有函数或实例都直接或间接继承该对象的属性。
1)JS通过原型链实现继承。所有实例对象都自动拥有原型对象中的属性或方法。
function Person(){
this.test1=function(){
console.log("test1")
}
}
Person.prototype.test2=function(){
console.log("test2")
}
var p=new Person();
p.test1();
p.test2();
console.log(p.toString())
2)原型链就是查找对象对象的属性,设置对象属性时,不会到原型链中查找。
>>>>>> 案例1:原型链只能用于查找对象的属性。设置对象的属性时,不会查找原型链。
function Person(){
}
Person.prototype.a=12;
var s=new Person();
console.log(s.a); //12
var s2=new Person();
s2.a=1222;
console.log(s.a); //12
console.log(s2.a); //1222
>>>>>> 案例2:调用原型对象的方法,原型对象的方法中的this指的也是传入的对象
function Person(){
}
Person.prototype.setName=function(name){
this.name=name;
};
var s=new Person();
s.setName("123")
var s2=new Person();
console.log(s)
console.log(s2)
2.2 原型链内部原理图
1)原型链的原理图
function Person() {
this.test1 = function () {
console.log("test1")
}
}
Person.prototype.test2 = function () {
console.log("test2")
}
var p = new Person();
p.test1();
p.test2();
console.log(p.toString())
解析:
p.test1() 首先查找到p对应的内存,查找test1属性,找到后调用即可。
p.test2() 首先查找到p对应的内存,查找test2属性,找不到,
就会沿着__proto__属性指向的原型对象中查找。
p.toString() 首先查找到p对应的内存,查找toString属性,找不到,
就会到p对应的原型对象中查找,找不到。
再次到原型对象的原型对象中查找。
2)Object、Function内部原理图
1、所有函数都有一个显示原型属性,它默认指向一个Object空实例对象,即原型对象。
但是Object除外。
2、所有对象都有一个隐式原型属性,它默认指向构造函数显示原型属性指向的原型对象。
3、所有函数都是Function的实例。(包含Function也是Function的实例)
1) 所有函数都有显示原型属性和隐式原型属性。
所有函数的隐式原型属性都指向构造函数Function显示原型属性指向的原型对象。
2) Function的隐式原型等于Function的显示原型。他们都指向同一个原型对象。
3)原型链原理测试案例
>>>>>> 解析案例1
function Person(){}
Object.prototype.a=function(){console.log("a")}
Function.prototype.b=function(){console.log("b")}
var s=new Person();
s.a(); //可以输出
s.b; //报错
Person.a(); //可以输出
Person.b(); //可以输出
>>>>>> 解析案例2
function A(){}
A.prototype.n=1;
var b=new A();
A.prototype={
n:2,
m:3
};
var c= new A();
console.log(b.n, b.m , c.n , c.m) //1 undefined 2 3
2.3 总结
1、每个函数都有一个prototype属性,即显示原型。它默认指向一个Object空实例对象,即原型对象。
但是Object函数除外。Object函数指向的原型对象不是Object类型。
2、每个对象都有一个__proto__属性,即隐式原型。它默认指向构造函数显示原型指向的原型对象。
3、实例对象隐式原型属性的值等于构造函数显示原型的值,它们都指向原型对象。
4、构造函数与原型对象互相引用。
5、所有函数都是Function的实例,包括Function本身。
1) 每个函数都有显示原型与隐式原型。
并且每个函数的隐式原型都同时指向Function显示原型指向的原型对象。
2) Function函数是它自身的实例。所以Function函数的隐式原型和显示原型都指向同一个原型对象。
Function.__proto__=Function.prototype
6、Object.prototype是原型链的尽头。
由于Object.prototype.__proto__为null。所以Object的原型对象是原型链的尽头。
7、所有函数的原型对象默认都是Object实例,但是Object函数的原型对象不是Object实例。
1)所有函数都是Function的实例,包括Function本身
声明一个函数或创建函数对象两者等价:
function Person(){ }
var Person=new Function();
>>>>>> 每个函数都有隐式原型和显示原型。并且每个函数的隐式原型都同时指向Function显示原型指向的原型对象。
function Person(){
}
function Person2(){
}
//每个函数都有一个隐式原型,它默认指向一个空实例对象
console.log(Person.prototype);
//所有函数都是Function的实例。所以每个函数都拥有隐式原型和显示原型
console.log(Person.__proto__);
//由于所有函数都是Function的实例。所以函数隐式原型都同时指向Function函数的显示原型指向的原型对象。
console.log(Person.__proto__===Function.prototype);
console.log(Person2.__proto__===Function.prototype);
>>>>>> Function函数对象是它自身的实例,所以Function的隐式原型和显示原型相等。
//var Function = new Function()
console.log(Function.prototype===Function.__proto__)
2)每个函数的显示原型都默认指向一个Object空实例对象。但是Object函数的显示原型对象除外。
function Person(){}
console.log(Person.prototype instanceof Object) //true
console.log(Function.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
3)Object函数的原型对象是原型链的尽头。主要是由于它的原型对象的隐式原型为null。
console.log(Object.prototype.__proto__) //null
三、instanceOf 判断(实质上就是原型链的应用)
1、instanceOf 判断。实质上就是依赖于原型链。
2、表达式: A instanceOf B
判断B的显示原型指向的原型对象是否在A的原型链中。如果是,返回true。、
console.log(Object instanceof Function); //true
console.log(Object instanceof Object); //true
console.log(Function instanceof Function); //true
console.log(Function instanceof Object); //true
function Person(){}
console.log(Object instanceof Person); //false