2017-10-13 10:14:59
首先来说一下名词解释,首先说一下prototype,每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用new操作符调用)的时候,新创建的对象会从原型对象上继承属性和方法。
再来说一下constructor,对象的constructor属性用于返回创建该对象的函数,也就是我们常说的构造函数。
至于__porto__属性,在 javascript 中每个对象都会有一个 __proto__ 属性,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去 __proto__ 里找这个属性,这个 __proto__ 又会有自己的 __proto__,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
先来看一个例子
function ab(){}
console.log(ab.prototype.constructor===ab);//输出结果为true
如上,当我们创建一个函数,系统就会为这个函数自动分配一个prototype指针,指向它的原型对象。并且可以发现,这个原型对象包含两个部分(constructor 和 __proto__)其中constructor指向函数自身。
当我们将该函数作为模版创建实例(new方法)的时候,我们发现创建出的实例是一个与构造函数同名的object,这个object是独立的,他只包含了一个__proto__指针(实例没有prototype,强行访问则会输出undefined),这个指针指向上面提到的构造函数的prototype原型对象。
这时候我们发现三者形成了一个大"闭环"。之所以加上引号,因为构造函数和实例之间无法直接访问,需要通过__proto__指针间接读取。
function ab(){}
var c = new ab();
console.log(c.__proto__===ab.prototype);//输出结果为true
console.log(c.__proto__.constructor==ab);//输出结果为true
其实这几个的关系可以通过下图来表现明确一些:
在javascript当中除了undefined和null外都有__proto__,但是只有function对象才有prototype属性,其他任何类型的值都没有。即使是使用new方法从function构造出的实例对象也没有prototype属性。但是我们可以通过赋值的形式来给他添加,例如:
var test={};
test.prototype=a{s:"这个是对象的值"}
console.log(test.portotype.s);//输出结果为:这个是对象的值
下面我们在看一下下面这个例子
function md(){};
var a = new md();
md.prototype = function ef(){}
console.log(a.prototype);//输出结果为undefined
b = new md();
console.log(b.prototype);//输出结果为object
console.log(b.prototype.constructor);//输出结果为function ef(){}
我们可以发现,改变了prototype之后创建的实例指向了新的prototype对象,而之前的依然指向老的prototype对象。
下面是个应用这个方法拓展实例的小例子:
var shape = function(){
}
var p={
a:function(){
console.log("啊啊啊啊啊啊");
}
}
shape.prototype = p;
var circle = new shape();
circle.a();//将会输出:啊啊啊啊啊啊