对象属性、原型与原型链
哈哈哈,我的第二篇博客哟,说的是对象属性、原型与原型链。可能这些只是某些小点串联起来的,逻辑性没有很强。所以会对文章的可读性和理解性带来一些困扰。不过,今天我又前进了那么一小步,为之后的学习又打下了那么一丢丢的基础,虽然理解的不是特别好,不过我还会理解第二次,第三次。恩。加油!
【对象】
对象中包含一系列的属性。这些属性都是无序的,每个属性都有一个字符串key和对应的value。
创建自定义对象的最简单方式就是创建一个object实例,然后再为它添加属性和方法。
属性类型:数据属性和访问属性。
数据属性:
configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性等。这个特性默认值为true。
enumerable:表示能否通过for-in循环返回特性。这个特性默认值为true。
writable:表示能否修改属性的值。这个特性默认值为true。
value:包含这个属性的数据值。读取属性值的时候,在这个位置读取,写入属性值的时候,把新值保存在这个位置。这个特性默认值为undefined。
要修改默认属性,必须使用Object.defineProperty()方法。
可以多次调用Object.defineProperty()方法修改同一个属性,但把configurable特性设置为false之后就会有限制了。
访问器属性:
访问器属性不包含数据值,他们包含一对getter和setter函数(非必需)。getter函数负责返回有效的值;setter函数负责如何处理数据。
访问器属性一共有四个特性,除了configurable和enumerable之外,还有get和set方法,get在读取属性时被调用,set在写入属性时被调用。且默认值都为undefined。
在不支持Object.defineProperty()方法的浏览器中不能修改configurable和enumerable。
【原型与原型链】
原型模式:我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象包含可以由特定类型的所有实例共享属性和方法,而使用原型对象,可以让所有对象实例共享它所包含的属性和方法。字面理解的话,prototype就是通过调用构造函数而创建那个对象实例的原型对象。
原型对象:无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。
使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中。原型返回false,实例返回true。
原型与in操作符:in操作符可以单独使用,也可以在for-in循环中使用,而且同时使用in操作符和hasOwnProperty()就可以确定属性到底存在于对象还是原型中。如:
function Person(){}
Person.prototype.name="smile";
Person.prototype.age=19;
Person.prototype.sayName=function(){
alert(this.name);
};
var person1=new Preson();
alert(person1.hasOwnProperty("name"));//false
alert("name" in person1); //true
只要in操作符返回true,hasOwnProperty()返回false,就可以确定属性是原型中的属性。
原型链:原型链是实现继承的主要方法。基本思想是利用原型让一个引用类型继承另一个引用类型的方法。对于构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包括一个指向构造函数的指针,而实例都包含一个指向对象内部的指针。假如我们让原型对象等于另一个类型实例,那么此时的原型对象包含一个指向另一个原型指针,相应的,另一个原型也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,如此层层递进,就构成了实例与原型的链条。这就是原型链的基本概念。而且,在原型链的末端一定是null。
在通过原型链实现继承的情况下,搜索过程就得沿着原型链继续向上。
所有引用类型默认都继承了Object,而这个继承是通过原型链来实现的。所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。
原型链的问题:
原型链中的包含引用类型值的原型属性会被所有实例共享,而这也是为什么要在构造函数中,而不是原型函数中定义属性的原因。在通过原型实现继承时,原型实际上会变成另一个类型的实例。于是,原先的属性也顺理成章的变成了现在的原型属性了。
在创建子类型的实例时,不能向超类型的构造函数中传递参数。