原型与原型链
一、prototype 和 __proto__的区别
- 我们每创建一个函数,解析器都会向里添加一个
prototype
属性,该属性指向函数的原型对象。 __proto__
是每个对象都有的隐含属性。
var obj = {};
console.log("obj.prototype:",obj.prototype);
console.log("obj.__proto__:", obj.__proto__);
var fun= function () { }
console.log("fun.prototype:", fun.prototype);
console.log("fun.__proto__:", fun.__proto__);
每个对象都有
__proto__
属性,但只有函数对象才有prototype
属性
二、验证__proto__ 指向
一个对象的
__proto__
属性指向创建该对象的构造函数的原型,这也保证了实例能够访问,在构造函数原型中定义的属性和方法。
__proto__
是每个对象有的属性,那我们就从对象下手,下面列举几种常见创建对象的方式,来看看他们的__proto__
指向。
- 字面量方式
let obj = {};
console.log("obj.__proto__:", obj.__proto__);
console.log( obj.__proto__ === obj.constructor.prototype);
- 构造器方式
let Fun = function() {};
let obj = new Fun();
console.log("obj.__proto__:", obj.__proto__);
console.log(obj.__proto__ === obj.constructor.prototype);
- Object.create()方式
var obj1 = { a: 1 }
var obj2 = Object.create(obj1);
console.log(obj2.__proto__);
console.log(obj2.__proto__ === obj1.constructor.prototype);
三、原型
在
JavaScript
中,每当我们创建(或声明)一个函数,浏览器都会向里面添加一个prototype
属性,该属性的值对应着一个对象,指向了当前函数的引用地址。这个对象就是我们所谓的原型对象,简称函数的原型。原型对象有一个默认属性constructor
,该属性指向了这个函数 (即:constructor
属性的值是这个函数 )。
//声明一个函数Person
function Person() {}
声明一个 Person 函数后发生的事情:
Person
就是构造函数,Person.prototype
就是原型
如果Person
函数作为普通函数调用,那么 prototype
作用不大,可以说是没有任何作用,但以构造函数的形式调用时,它所创建出的对象中都会有一个隐含的__proto__
属性,该属性指向创建它的构造函数的原型对象。
function Person () {}
var p1 = new Person();
console.log("p1.__proto__:", p1.__proto__);
上面代码示意图:
简易图:
构造函数
Person
,也可以称之为类
通过构造函数Person
创建的对象p1
,可称为实例对象
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象。
function Person() {}
Person.prototype.x = 10;
Person.prototype.y = 20;
var p1 = new Person();
p1.z = 30;
var p2 = new Person();
p2.z = 40;
console.log("p1.x:", p1.x, "p1.y:", p1.y, "p1.z:", p1.z);
console.log("p2.x:", p2.x, "p2.y:", p2.y, "p2.z:", p2.z);
输出结果:
上面代码的示意图:
四、原型链
当我们访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的
__proto__
隐式原型上查找,即它的构造函数的prototype
,如果还没有找到就会再在构造函数的prototype
的__proto__
中查找,最后会到达顶层的Object prototype
,它的__proto__
指向null
,均无结果最后则返回undefined
,结束。这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
function Fun(){};
var f = new Fun();
console.log(f.__proto__);
console.log(f.__proto__.__proto__);
console.log(f.__proto__.__proto__.__proto__);
执行结果:
画图理解:
简易版图解:
五、玄学
函数(function)概念:函数简单的说就是可以重复执行的代码块。( 只定义一次,但可能被执行(或调用)任意次的一段
JavaScript
代码块)
构造函数(constructor):一种专门创建对象时使用的特殊函数。
Object
的生成
function Object
同时也是一个对象,它的原型是Function.prototype
,该原型用来描述所有的函数。
console.log(Object.__proto__ === Function.prototype);
console.log(Function.__proto__ === Function.prototype);
console.log(Function.prototype.__proto__ === Object.prototype);
console.log(Object.prototype.__proto__ === null);
运行结果:
看图理解:
总结起来就是:鸡生蛋蛋生鸡。