JS对象与原型.docx
- 文档编号:30201499
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:18
- 大小:2.61MB
JS对象与原型.docx
《JS对象与原型.docx》由会员分享,可在线阅读,更多相关《JS对象与原型.docx(18页珍藏版)》请在冰豆网上搜索。
JS对象与原型
面向对象设计-->引用类型(functionstringnumberarraydate)----->Object---->对象原型----->函数表达式--->数据类型
面向对象:
类和对象,通过类可以创建任意多个具有相同属性和方法的对象。
ECMA定义对象:
无序属性的集合,其属性可以包含基本值、对象或者函数。
相当于一组没有特定顺序的值,对象的每个属性或方法都有一个名字,而每个名字映射到一个值。
即:
对象就是一组键值对,其中值可以是数据或函数。
每个对象都是基于一个引用类型创建的。
Object是所有JS对象的基类
prototype是对象的原型
obj.constructor是创造该对象的构造器
一、创建自定义对象
varperson=newObject();
person.name="dujie";
person.say=function(){alert(this.name)};
字面量法:
varperson={
name:
"dujie",
say:
function(){alert(this.name);}
}
二、对象属性
内部采用的特性,描述了属性的各种特征,这些特性是为了实现JavaScript引擎用的,在js中不能直接访问,为了表示特性是内部值,规范把他们放在了两对方括号里例如:
[[Enumerable]]
ECMAScript中有两种属性:
数据属性和访问器属性
1.数据属性:
包含一个数据值的位置,行为(在这个位置可以读取和写入值)
4个描述行为:
@1.[[Configurable]]:
表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性或者能否把属性修改为访问器属性。
默认值为true
@2.[[Enumerable]]:
表示能否通过for-in循环返回属性,默认为true
@3.[[Writable]]:
表示能否修改属性的值默认为true
@4.[[Value]]:
包含这个属性的数据值。
默认为undefined,从这个位置读取或写入保存属性的值
定义对象时varperson={name:
"dujie"}[[Value]]特性将被设置为"dujie"
若要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法
Object.defineProperty(obj,"属性名",描述符对象)
描述符对象的属性必须是configurableenumerablewritablevalue
例如:
varperson={};
Object.defineProperty(person,"name",{
writable:
false,属性值不可以修改,变成只读
configurable:
false不可从对象中删除属性deleteperson.name无效果
value:
"dujie"
});
alert(person.name)//dujie
person.name="jack";
alert(person.name)//dujie
注意:
可以多次调用Object.defineProperty()方法修改同一属性的特性,但是把configurable特性设置为false后就会有限制,除writable之外的特性都会报错
原型对象
模仿类,实例化对象
实例化对象流程:
1.创建obj=newObject()
2.将obj的内部__proto__指向构造函数A的prototype属性,同时obj.constructor===A.prototype.constructor类的实例对象的constructor属性永远指向构造函数的prototype.constructor,
构造函数person
原型对象person.prototype
对象实例person1
三者的关系:
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
原型链:
原型对象等于另一个类型的实例,将包含一个指向另一个原型的指针,相应地另一个原型中也包含指向另一个构造函数的指针,层层递进,构成了原型连
在实例中无法访问prototype属性,可通过isPrototypeOf()方法来确定对象之间是否存在这种关系
person.prototype.isPrototypeOf(person1)//返回true因为person1内部有一个指向person.prototype的指针,所以返回true
如果实例中的prototype指向调用isPrototypeOf()方法的对象(person.prototype),就返回true
ECMAScript5增加方法:
Object.getPrototypeOf()返回[[Prototype]]的值(对象原型)
(IE9+Firefox3.5Safari5+Opera12+Chrome支持此方法)
alert(Object.getPrototypeOf(person1)==person.prototype);//true
alert(Object.getPrototypeOf(person1).name);
原型模式执行流程:
读取实例属性值:
1.先从对象实例开始搜索,有则返回该属性的值,没有继续根据链接搜索原型对象,最后返回原型中的属性值
2.不能通过对象实例重写原型中的值,如果在实例中添加了一个与原型中具有相同名字的属性,那么就在实例中创建该属性,该属性会屏蔽原型中的属性(但不会修改原型中的属性值)
解除屏蔽:
即使在实例中把属性设置为null也只会在实例中设置这个属性,而不会恢复其指向原型的链接,可以使用delete操作符完全删除这个实例属性,让我们重新访问原型中的属性。
functionperson(){}
person.prototype.name='dujie',
person.prototype.age=25,
person.prototype.say=function(){
console.log(this.name);
}
varperson1=newperson();
varperson2=newperson();
person1.name='lili';
console.log(person1.name);//lili
console.log(person2.name);//dujie
deleteperson1.name;
console.log(person1.name);//dujie
console.log(person2.name);//dujie
hasOwnProperty()方法:
检测一个属性存在于实例中还是在原型中(这个方法只在属性存在于对象实例中时才返回true)
person1.hasOwnproperty("name");//实例中有返回true无返回false
通过此方法,判断访问的是实例属性还是原型属性就一清二楚了
Object.getOwnPropertyDescriptor(person1,'name')只运用于实例属性,要取得原型对象属性描述符,必须直接在原型对象上调用Object.getOwnPropertyDescriptor()方法
原型于in操作符
in操作符在单独使用时,会在通过对象能够访问给定属性时返回true无论属性存在于实例中还是原型中
person1.hasOwnProtoperty("name");//返回false在原型中
alert("name"inperson1)//返回true
可同时使用hasOwnProperty()方法和in操作符,确定该属性是在原型中还是在实例中
functionhasPrototypeProperty(object,name){
return!
object.hasOwnProperty(name)&&(nameinobject);
}
确定属性是在原型中的属性
for(iinobj):
返回所有能够通过对象访问的,可枚举的属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。
@.取得对象中所有可枚举的实例属性,可使用Object.keys()方法,接受一个对象作为参数,返回一个包含所有可枚举的属性的字符串数组
实例的话,只返回实例中的属性
原型:
只返回原型中的属性
Object.getOwnPropertyNames(obj)获得所有实例属性,无论是否可枚举
实例的话,只返回实例中的属性
原型:
只返回原型中的属性
为什么会指向Object?
Box.prototype={}相当于新创建了一个对象,而每创建一个函数,就会同时创建它的prototype,这个对象也会自动获取constructor属性,所以新对象的constructor重写了Box原来的constructor,因此指向新对象,新对象没有构造函数,就是默认的Object
解决:
@原型语法简化:
functionPerson(){}
Person.prototype={
constructor:
Person//确保该属性指向构造函数
name:
'dujie',
age:
25,
say:
function(){}
};
目的:
简化person.protorype的重复写
弊端:
constructor属性不在指向person了
此种写法:
相当于重写(重新定义了一个对象)了prototype对象,因此constructor属性也就变成了新的对象的constructor属性(指向Object构造函数),不再指向person函数,因此通过constructor已经无法确定对象的类型了
如上:
person1.constructor==person//false
person1.constructor==Object//ture
可以在重写对象时加上constructor:
Person,但是重写会导致他的[[Enumerable]]特性设置为true,默认情况下原生的constructor属性是不可枚举的,如想兼容ECMAScript5可以通过Object.defineProperty()设置
Object.defineProperty(Person.prototype,"constructor",{
enumerable:
false,
value:
Person
})
原型的声明是有先后顺序的,所以重写的原型会切断之前的原型。
原型的动态性:
实例中的指针仅指向原型,而不指向构造函数
functionPerson(){}
varfriend=newPerson();//创建person实例,指向person原型
Person.prototype={//重写了原型对象
constructor:
Person,
name:
'dujie',
age:
25
}
varper=newPerson();
console.log(friend.name);//undefined//调用属性时发生错误,因为friend指向的原型中不包含该属性
console.log(per.name);//dujie//重写原型后实例化,具有该属性返回
重写原型对象截断了现有原型于任何之前已经存在的对象实例之间的联系,他们引用的任然是最初的原型。
原型对象不仅仅可以再自定义的对象的情况下使用,而ECMAScript内置对象的引用类型都可以使用这种方式,并且引用类型本身也使用了原型。
原生引用类型都是这么创建的(ObjectArrayString等)都在其构造函数的原型上定义了方法
Array.prototype.sort
String.prototype.substring
可以取得默认的方法,也可以定义新的方法
组合使用构造函数于原型模式
构造函数:
定义实例属性
原型模式:
定义方法和共享属性
functionPerson(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.friend=['lili','liing'];
}
Person.prototype={
constructor:
Person,
sayName:
function(){
console.log(this.name);
}
}
varperson1=newPerson('dujie',25,'programe');
varperson2=newPerson('limeng',25,'doctor');
person1.friend.push('van');
console.log(person1.friend);
console.log(person2.friend);
console.log(person1.friend===person2.friend);
console.log(person1.sayName===person2.sayName);
["lili","liing","van"]
["lili","liing"]
false
true
原型模式:
不管你是否调用了原型中的共享方法,它都会初始化原型中的方法,并且声明一个对象时,构造函数+原型的模式分开写不方便维护,最好把构造函数和原型封装到一起,为了解决这个问题,可使用动态原型模式
动态原型模式
:
把所有信息都封装在构造函数中,通过在构造函数中初始化原型,又保持了同时使用构造函数与原型的优点(通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型)
functionPerson(name,age,job){
this.name=name;
this.age=age;
this.job=job;
if(typeofthis.sayName!
="function"){//仅在第一次调用时初始化
Person.prototype.sayName=function(){}
}
}
varfriend=newPerson('dujie',25,"SoftwareEngineer");
friend.sayName();
第一次调用构造函数时,sayName()方法不存在,然后初始化原型,第二次调用时,就不会初始化,并且第二次创建新对象,原型也不再初始化了。
注意:
使用动态原型模式,不可以再使用字面量的方式重写原型,因为会切断实例和原型之间的联系。
二、原型连实现继承
基本思想:
利用原型让一个引用类型继承另一个引用类型的属性和方法
构造函数原型实例之间的关系:
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针
让原型对象等于另一个类型的实例:
此时原型对象将包含另一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。
假如另一个原型又是另一个类型的实例,上述关系依然成立,层层递进,就构成了实例于原型的链条,成为原型链。
functionSuperType(){
this.name='dujie';
}
SuperType.prototype.getSuperValue=function(){
returnthis.name;
}
functionSubType(){
this.age='100';
}
SubType.prototype=newSuperType();//子类原型继承了父类实例
SubType.prototype.getSubValue=function(){
returnthis.age;
}
varinstance=newSubType();
alert(instance.getSuperValue());dujie//调用父类中的方法
继承通过:
创建超类实例,并将该实例赋值给子类的原型来实现,实现的本质是重写原型对象,代之以一个新类型的实例。
原来存在于超类实例中的所有属性和方法,现在也存在于子类的原型中了,确立继承关系后,我们给子类原型添加了一个新的方法,这样在继承了超类的属性和方法的基础上又添加了一个新的方法。
3.方法定义
2.在通过原型链实现继承时,不能使用对象字面量创建原型方法,这样做会重写原型链。
原型链的问题:
1.包含引用类型值得原型,引用类型的原有属性值会被所有实例共享
2.在创建原型链的时候不能向超类中传参
解决原型值带来的问题:
组合式继承:
将原型链和借用构造函数的技术组合到一起
思路:
使用原型链实现对原型属性和方法的继承。
而通过借用构造函数来实现对实例属性的继承。
通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JS 对象 原型