1、所有的引用类型(数组、对象、函数)都具有对象特性,即可自由扩展属性(除了“null”)
var array=[];array.a=1;
var object={};object.a=1;
function func(){};
func.a=1;
2、所有的引用类型(数组、对象、函数)都有一个__proto__属性(隐式原型属性),属性值是一个普通的对象
console.log(array.__proto__);
console.log(object.__proto__)
console.log(func.__proto__)
3、所有的函数,都有一个 prototype(显式原型)属性,属性值也是一个普通的对象
console.log(func.prototype)
4、所有的引用类型(数组、对象、函数),__ proto__(隐式原型)属性值指向它的构造函数的“prototype”属性值
console.log(array.__proto__===Array.prototype); //true
console.log(object.__proto__===Object.prototype); //true
console.log(func.__proto__===Function.prototype); //true
5、当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的_proto_(即它的构造函数的 prototype(显式原型))中寻找
function Person(){};
Person.prototype.name = "小明";
var p1 = new Person();
var p2 = new Person();
p1.name="小红"
console.log(p1.name); // 小红 来自实例
console.log(p2.name); // 小明 来自原型
二、原型链
原型链是实现继承的主要方法。
原型链的思路:
查找属性,如果本身没有,则会去__proto__中查找,也就是构造函数的显式原型中查找,如果构造函数中也没有该属性,因为构造函数也是对象,也有__proto__,那么会去它的显式原型中查找,一直到null,如果没有则返回undefined。
举一个比较典型的例子:
Function.prototype.a = "a";
Object.prototype.b = "b";
function Person(){}
let p = new Person();
console.log(p); //Person {}
console.log(p.a); //undefined
console.log(p.b); //b
可能有人会有疑问,为什么p没有继承Function原型里面的属性,其实Person()才是Function对象的一个实例,new Person()返回来的是一个对象,是Object的一个实例,没有继承Function,无法访问Function原型的属性。
console.log(Person.__proto__===Function.Prototype) //true
按照思路进行查找:
console.log(p.__proto__) //返回Person.prototype
console.log(p.__proto__.__proto__) //返回Object.prototype
所以p.b打印结果为b,p没有b属性,会一直通过__proto__向上查找,最后当查找到Object.prototype时找到,最后打印出b,向上查找过程中,得到的是Object.prototype,而不是Function.prototype,找不到a属性,所以结果为undefined,这就是原型链,通过__proto__向上进行查找,最终到null结束(Object.prototype.__ proto__===null)。
顺便一提,js里面所有的对象都是Object的实例,Person()函数也是可以访问到Object原型的属性。
console.log(Person.b) //b
最后盗张图帮助理解