JavaScrip之对象与继承
这章主要学习对象、原型、原型链和继承,比较核心,所以单独整理这一章的内容。
理解对象:一组名值对,值可以是数据或函数。
属性类型:1数据属性:包含一个数据值的位置。在这个位置可以读取和写入值,4个描述其行为的特性:
[[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认true;
[[Eenmuerable]]表示能否通过for-in循环返回属性,默认true;
[[Writable]]表示能否修改属性的值,默认true;
[[value]]:包含这个属性的值。读取属性的时候,从这个位置读,写入属性值的时候,把新值保存在这个位置,默认undefined.
要修改属性默认的特性,必须使用ECMAScript的Object.defineProperty()方法 Object.defineProperty(Person(对象名),"name属性",{
writable:false,value:...
})
2访问器属性:不包含数据值;包含一对getter和setter函数(不是必须),在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性的时候,会调用setter函数并传入新值,这个函数负责决定如何处理数据。
[[Configurable]]表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性,默认true;
[[Eenmuerable]]表示能否通过for-in循环返回属性,默认true;
[[get]]在读取属性时调用的函数,默认undefined
[[set]]在写入属性时调用的函数,默认undefined
访问器属性不能直接定义,须使用ECMAScript的Object.defineProperty()方法
var book={
_year:2004,
edition:1
}
Object.property(book,"year",{
get:function(){return this.year},
set:function(newValue){if(newVlaue>2004){this._year=newValue;this.edition+=newValue-2004;}}
})
book.year=2005;
alert(book.edition);
6.2创建对象:
1工厂模式:用函数来封装以特定接口创建对象的细节
function creatPerson(name,age,job){
var o=new Object();
o.name=name;
o.age=age;
o.job=job;
o.sayName=function(){
alert(this.name);
};
return o;
}
var person1=creatPerson('zhangfei',29,'killer');
var person2=creatPerson('guanyu',30,'killer');
2构造函数模式:创建自定义的构造函数,从而定义自定义对象类型的属性和方法
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
this.sayName=function(){
alert(this.name);
};
}
var person1=new Person('zhangfei',29,'killer');
var person2=new Person('guanyu',30,'killer');
特点:没有显式的创建对象,直接将属性和方法赋给了this对象,没有return语句。
创建Person新实例:1创建一个新对象,2将构造函数的作用域赋值给新对象(this指向了这个对象);3执行构造函数中的代码(为新对象添加属性)4返回新对象
存在问题:每个方法都要在每个实例上重新创建一遍(我的理解是每创建一个实例,实际上构造函数中的方法都是重新执行,创建了新的函数)
解决方案:原型模式
原型模式:重点中的重点.利用书中的图示,可以很好地理解,自己画一遍可以了。
1 原型对象:只要创建新函数,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象。所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性指向prototype属性所在函数
创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性,当调用构造函数创建一个新实例后,该实例的内部包换一个指针[[Prototype]],指向构造函数的原型对象。(可以在Chrome浏览器中看到,即_proto_),这个连接存在于实例和构造函数的原型对象之间,而不存在于实例和构造函数之间。
可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。 Person.prototype.isPrototypeOf(person1)
Object.getPrototypeOf(person1)方法可以返回[[prototype]]的值。
当代码读取某个对象的属性时,会执行一次搜索,目标是具有给定名字的属性,搜索首先从对象实例本身开始,找到则返回,找不到则继续搜索指针指向的原型对象,如果在原型对象中找到,则返回
(实例中添加一个属性,如果与实例原型对象中的属性同名,会屏蔽但不会修改原型对象中的值)
使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,来自实例true,来自原型:false
e: function Person() { }
Peraon.protopyty = {
constructor:Person, //这里使用字面量来简写,本质上重写了prototype对象,这里定义它指向Person构造函数
name: '张飞',
age: 29,
job: 'killer',
sayName: function () { }
}
var person1 = new Person();
var person2 = new Person();
person1.hasOwnPorpertype('name')//false
person1.name = '李典';
person1.hasOwnPorpertype('name')//true
console.log(person1.name);//李典
console.log(person2.name);//张飞
delete person1.name;
console.log(person1.name);//张飞
原型与in操作符:单独使用in:对象能够访问属性就返回true alert('name' in person1) //true
问题:原型对象中的属性被所有实例共享,对于包含引用类型值的属性来说,就存在问题了,一个实例中属性变,导致都变。
组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定于方法和共享的属性e:
function
Person(name,skill,country) {
this.name=name;
this.skill=skill;
this.country=country;
this.member=["刘封","刘婵"];
}
Person.prototype={
constructor:Person,
sayUseSkill:function () {
alert(this.skill);
}
}
var person1=new Person('马超','铁骑','蜀国');
var person2=new Person('刘备','仁德','蜀国');
person1.member.push('关羽');
console.log(person1.member);
console.log(person2.member);
console.log(person1.member===person2.member);//false
console.log(person1.sayUseSkill===person2.sayUseSkill);//true
动态原型模式:在构造函数中初始化原型对象
function
Person(name,skill,country) {
this.name=name;
this.skill=skill;
this.country=country;
if(typeof this.sayCountry !=undefined){
Person.prototype.sayCountry=function () {
alert(this.country);
};
}
}
var
friend=new Person('张飞','咆哮','蜀国');
friend.sayCountry();
6.3 继承 涉及到原型链
原型链:(继承:原型对象等于另一个类型的实例) 思想:利用原型让一个引用类型继承另一个引用类型的属性和方法
首先先滤清构造函数、原型对象、实例之间的关系:每个构造函数有一个原型对象(构造函数有一个prototype属性指向原型对象),而原型对象有一个constructor属性指向构造函数,而实例中有一个内部属性(指针)[[Prototype]]指向原型对象。
如果然原型对象等于另一类型的实力,那么这个原型对象将包含指向另一个原型对象的指针,然后(另一个原型对象)又是第三个函数的实例,那么依然如上述,层层递进,就构成了原型链。虽然看着绕,但是动手画一画就很明晰了(我的理解是父函数的实例是子函数的原型)。
例子:(添加了注释,这样看着图非常容易理解)
//父函数,他的实例中有[[Prototype]]属性和自定义的property属性
function SuperType(){
this.property=true;
}
//在SuperType原型对象中添加getSuperValue方法
SuperType.prototype.getSuperValue=function(){
return this.property
}
//子函数,构造函数SubType,它的实例中有[[Prototype]]属性和自定义的subproperty属性
function SubType(){
this.subproperty=false;
}
//继承了SuperType (原型链)
SubType.prototype=new SuperType();
//在SubType原型对象中添加getSubValue方法
SubType.prototype.getSubValue=function(){
return tis.subproperty;
};
var insatance=new SubType();
alert(insatance.getSuperValue()); //true
谨慎的定义方法:子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。给原型添加方法的代码一定要放在替换原型的语句之后。
存在问题:还是引用类型值会改变,因为实例共享属性。
经典继承(借用构造函数)
在子类构造函数的内部调用超类构造函数
相当于把父类的属性实例化到子类中?Java中的super() 存在疑问
function SuperType(){
this.colors=['red','blue','green'];
}
function SubType(){
//继承了SuperTYpe
SuperType.call(this);
}
var insatance1=new SubType();
insatance1.colors.push('black');
alert(insatance1.colors);// 'red,blue,green,black'
var insatance2=new SubType();
alert(insatance2.colors);//'red,blue,green'
1传递参数:
借用构造参数可以在子类型构造参数中向超类型构造参数传递参数
function SuperType(name){
this.name=name;
}
function SubType(){
//继承了SuperTYpe,同时还传递了参数
SuperType.call(this,'赵云');
//实例属性
this.age=29;
}
var insatance=new SubType();
alert(insatance.name); //赵云
alert(insatance.age); //29
为了确保SuperType构造函数不会重写子类型的属性,可以在调用超类型构造函数之后,再添加应该在子类型中定义的属性。
问题:方法都在构造函数中定义超类型中的方法对子类型不可见。
组合继承
原型链和构造函数技术组合到一起,使用原型链实现对原型属性和方法的继承,借用构造函数来实现对实例属性的继承。这样通过在原型上定义方法实现了函数的复用,有能够保证每个实例都有它自己的属性
原型继承:方法可以,实例属性无法继承; 借用构造函数:实例属性可以,方法不行。 一起用,完美。
function SuperType(name){
this.name=name;
thi.colors=['red','blue','green'];
}
SuperType.prototype.sayName=function(){
alert(this.name);
};
function SubType(name,age){
//继承属性
SuperType.call(this,name);
this.age=age;
}
//继承方法
SubType.prototype=new SuperType();
SubType.prototype.sayAge=function(){
alert(this.age);
}
var instance1=new SubType('zhaoyun',29);
instance1.colors.push('black');
alert(instance1.colors); //'red,blue,green,black'
instance1.sayName();//zhaoyun
instance1.sayAge();//29
var insatance2=new SubType('诸葛瑾',25);
alert(instance2.colrs);'red,blue,green'
instance22.sayName();//诸葛瑾
instance2.sayAge();//25
原型式继承
object()方法 function object(o){
function F(){};
F.prototype=o;
return new F();}
对传入的对象执行了一次复制,在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象最为这个构造函数的原型,最后返回了这个临时了新的一个新实例。
var person={
name:'张飞',
friends:['马超','刘备','赵云'];
}
var anothersPerson=object.create(person);
anothersPerson.name='孙权';
anothersPerson.friends.push('鲁肃');
var yetAnothersPerson=object.create(person);
yetAnohersPerson.name='曹操';
yetAnothersPerson.friends.push('关羽');
alert(person.friends);//马超,刘备,赵云,鲁肃,关羽
寄生式继承
使用hasOwnProperty()方法可以检测一个属性是存在于实例中还是存在于原型中,来自实例true,来自原型:false
e: function Person() { }
Peraon.protopyty
= {
name: '张飞',
age: 29,
job: 'killer',
sayName: function () { }
}
var person1 = new Person();
var person2 = new Person();
person1.name
= '李典';
console.log(person1.name);
console.log(person2.name);
delete person1.name;
console.log(person1.name);
寄生组合式函数
组合继承模式问题:会调用两次超类型构造函数,一次是在创建子类型原型的时候,另一次是在子类型构造函数内部,虽然子类型最终包含超类型对象的全部实例属性,但是在调用子类型构造函数时重写了这些属性。
function SuperType(name){
this.name=name;
this.colors=['red','blue','green'];
}
SuperType,prototype.sayName=function(){
alert(this.name);
};
function SubType(name,age){
SuperType.call(this.name);//第二次调用SuperTyper()构造函数,相当于java中的super()?又在新对象上创建了实例属性name 和colors,因此屏蔽了原型中的两个同名属性。
this.age=age;
}
SubType.prototype=new SuperType(); //第一次调用SuperType()构造函数,Subprototype会得到两个属性:name,colors,是父函数实例属性,位于子函数原型中
SubType.prototype.constructor=SubType;
SubType.prototype.sayAge=function(){
alert(this.age);
};
解决方案:巧用原型式继承,传入对象由父类型对象变为父类型对象的原型。
JavaScrip之对象与继承的更多相关文章
- js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。
js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } Class ...
- 对象的继承关系在数据库中的实现方式和PowerDesigner设计
原文:对象的继承关系在数据库中的实现方式和PowerDesigner设计 在面向对象的编程中,使用对象的继承是一个非常普遍的做法,但是在关系数据库管理系统RDBMS中,使用的是外键表示实体(表)之间的 ...
- 类和对象:继承 - 零基础入门学习Python038
类和对象:继承 让编程改变世界 Change the world by program 上节课的课后作业不知道大家完成的怎样?我们试图模拟一个场景,里边有一只乌龟和十条鱼,乌龟通过吃鱼来补充体力,当乌 ...
- #JavaScript对象与继承
JavaScript对象与继承 JavaScript是我在C语言之后接触的第二门编程语言,大一暑假的时候在图书馆找了一本中国人写的JavaScript程序设计来看.那个时候在编程方面几乎还是小白,再加 ...
- Javascript学习6 - 类、对象、继承
原文:Javascript学习6 - 类.对象.继承 Javasciprt并不像C++一样支持真正的类,也不是用class关键字来定义类.Javascript定义类也是使用function关键字来完成 ...
- (79)Wangdao.com第十五天_JavaScript 对象的继承_prototype原型对象_封装_函数式编程
javascript 内置了许多 function 函数(){...} js 执行首先就会执行自己内置的函数定义 (function Function.function Object) 对象的继承 大 ...
- Javascript实现对象的继承
在Java和C#中,你可以简单的理解class是一个模子,对象就是被这个模子压出来的一批一批月饼.压个啥样,就得是个啥样,不能随便动,动一动就坏了.而在Javascript中,没有模子,月饼被换成了面 ...
- 关于js的对象原型继承(一)
javascript中,对象的继承是通过原型去继承. 可以这样理解:js中的对象,包含的除了属性和方法,还有一个最基本的原型__proto__对象.这个原型__proto__指向谁,这个对象就继承谁. ...
- js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。
js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } ClassA ...
随机推荐
- TP-LINK WR841N V8刷OpenWRT
在某宝上淘了一个TP-LINK WR841N V8,已经硬改为8M闪存和64M内存,还刷好了Uboot.但是卖家刷好的系统是第三方定制过的OpenWRT,集成了很多不需要用到的软件,所以我要刷回官方原 ...
- WM_GETMINMAXINFO消息 中结构体MINMAXINFO
MINMAXINFO* lpMMI lpMMI->ptMaxSize.x = 800; // 设置窗口最大化时的宽度 lpMMI->ptMaxSize.y = 600; // 设置窗口 ...
- Xenko基础API笔记2-手势
交互: Drag Gesture Type : Continuous Configuration class: GestureConfigDrag Event class: GestureEventD ...
- jquery easyui校验select下拉列表值是否为空的问题
属性名 类型 描述 默认值 required 布尔 定义文本域是否为必填项 false validType 字符串 定义字段的验证类型,比如email, url, etc. null missingM ...
- Openstack Basic
html,body { } .CodeMirror { height: auto } .CodeMirror-scroll { } .CodeMirror-lines { padding: 4px 0 ...
- js 判断IOS版本号
先来观察 iOS 的 User-Agent 串: Phone 4.3.2 系统:Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; e ...
- session 丢失和解决方案
在ASP.NET的开发中,总遇到Session丢失.最常见的情况是当用户登录后将用户信息保存在Session中例如Session["user"]=user;在其后的页面中检查Ses ...
- python 功能代码安全高效写法
一. with 链接地址:https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/
- 第六百零九天 how can I 坚持
好失败啊,搞了一天,竟然连个环境都没搞好,也是醉了.还是太渣了. 洗澡,睡觉.
- Express安装过程
1,首选全局安装express,进入nodejs的安装目录执行以下语句 npm install -g express 2,安装工具 npm install -g express-generator 3 ...