原型?
在javascript中,每当定义一个对象(函数也是对象)时,对象中都会包含一些预定义的属性。其中当定义一个函数对象时,会生成prototype原型对象属性,这个属性指向函数的原型对象。原型对象中包含着所有实例共享的属性和方法,该原型对象有两个属性:__proto__和constructor。
每个对象实例都会在其内部初始化一个__proto__属性,他是一个指向prototype(原型对象)的指针,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,就会通过__proto__去prototype里找这个属性,这个prototype又有自己的__proto__指向自己的原型对象,于是就一直找下去,形成了原型链的概念。
原型链是什么?
JavaScript万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。
Object的原型对象是什么???
函数的原型对象constructor默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针_proto_,该指针指向上一层的原型对象,而上一层的原型对象的结构依然类似,这样利用_proto_一直指向Object的原型对象上,而Object的原型对象用Object.prototype._proto_ = null表示原型链的最顶端,如此便形成了javascript的原型链继承,同时也解释了为什么所有的javascript对象都具有Object的基本方法。
怎么判断一个属性是对象上的属性还是其原型对象上的属性?
obj.hasOwnProperty(attribute);
function fun(){} //因为fun()是Function的实例 fun.__proto__==Function.prototype;//true Function.prototype.__proto__==Object.prototype;//true; Object.prototype.__proto__==null//true
function Person(){} var person = new Person(); console.log(person.__proto__ === Person.prototype); // true 使用new操作符实例化的过程 function Person(){} // var person = new Person(); // 上一行代码等同于以下过程 ==> var person = {}; person.__proto__ = Person.prototype; Person.call(person);
假如我们让原型对象等于另一个类型的实例,结果会怎样的?显然,此时的原型对象将包含一个指向另一个函数原型的指针。(类似于实例化一个对象的过程)
son.prototype=new parent(); 等价于: var son.prototype={}; son.prototype.__proto__=parent.prototype; parent.call(son.prototype);
原型关系图:
原型链查找属性的顺序:__proto__
(1)首先在对象自身查找是否有该属性,如果有,返回结果;
(2)如果没有,就去对象的原型上进行查找,如果有,返回结果;
(3)如果没有,就沿着原型链继续往上查找,直到Object.prototype原型上,如果有,返回结果;
(4)如果Object.prototype原型上也没有,返回undefined
constructor属性也是对象才拥有的,它是从一个对象指向一个函数。即指向该对象的构造函数。
对于f1.constructor==Foo是因为f1对象本身不具有constructor属性,所以会通过__proto__属性向原型链中找,而f1.__proto==Foo.prototype,Foo.prototype具有constructor属性并且指向Foo函数,所以f1.constructor指向了Foo,它不是f1自身对象拥有的,是继承来的。
作用域链和原型链的区别
作用域链是针对变量的,比如我们创建一个函数,函数中又包含一个函数,此时就有三个作用域:全局作用域——函数1作用域——函数2作用域。
原型链是针对构造函数的,一般用于继承。