目录

1. JavaScrpt对象

2. 原型对象和继承

3. 对象的克隆

(1)javascript对象

  在JS中,对象是属性的容器。对于单个对象来说,都由属性名和属性值构成;其中属性名需要是标识符,而不能是字符串或者表达式,属性值可以是除undefined外的任何值。如果对象的属性值是函数,那么这个属性通常被称为方法。一般来说,对象可以通过直接量方式或者构造函数方式创建的,那么下面我用代码的方式更直观的展示对象的实现方式。(console.log在IE中无法工作,需要firefox或者Chrome浏览器方能正确显示)
  直接量方式:
var someone = {
name:'Tom',
age :,
work:'student',
showInfo:function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
str += this[name] + ' ';
}
}
console.log(str);
}
};
someone.showInfo(); //Tom 18 student
someone.hobby = 'music';
someone.showInfo(); //Tom 18 student music

从上面可以看出,直接量创建可以通过初始化时将已有对象赋值给它,也可以通过设置给对象添加新的属性,最后通过for/in循环就可以遍历出对象的所有属性,

构造函数方式:

//构造函数创建对象
function CreatPeople(name, age, work) //构造函数
{
this.name = name;
this.age = age;
this.work = work; this.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
str += this[name] + ' ';
}
}
console.log(str);
}
} var someone = new CreatPeople("Tom", , "student"); //实例对象
someone.showInfo(); //Tom 18 student var otherone = new CreatPeople("BoB", , "engineer");
otherone.showInfo(); //Bob 25 enginee

  对比直接量方式和构造函数方式创建的对象,它们具有相同的属性name, age, work以及方法showInfo,功能相同。其中构造函数方式可以通过函数实现多个不同对象的创建,不过当我们希望给CreatPeole创建的对象添加新的属性habby时,单独每个对象都添加就过于繁琐,为了方便上述过程,js引入不同于C++类方式的继承模式,具体详见下章:原型对象和继承。

(2)原型对象和继承

   JavaScript中每个对象都有原型对象,原型对象的所有属性都是以它为原型的对象的属性,也就是说,每个对象都继承原型对象的所有属性。JS中所有函数对象都有Prototype属性,它引用一个对象(原型对象), 虽然原型对象初始化时是空的,但你在其中定义的任何属性都会被该构造函数创建的对象继承。特别注意一点:被创建对象的继承是在查询时自动发生的,而并非直接复制,这样就大量减少了内存占有。类似与直接量添加属性的方式,我们也可以给函数通过prototype属性添加属性,此时由构造函数创建的实例对象就继承原构造函数的Prototype引用对象的全部属性。不过如果不希望修改原有对象,而只是借用已存在的构造函数相关接口,来实现新的构造函数,就需要使用JavaScript的子类化继承方式,实践如下:设计一个新构造函数ExtraCreatPerson,它继承了原有属性和方法,又在原有构造函数的基础上增加了hobby属性,从而实现对原有接口的扩展:

function CreatPeople(name, age, work){
this.name = name;
this.age = age;
this.work = work;
} CreatPeople.prototype.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
str += this[name] + ' ';
}
}
console.log(str);
} function ExtraCreatPeople(name, age, work, hobby){
CreatPeople.apply(this, arguments);
this.hobby = hobby;
}
ExtraCreatPeople.prototype = new CreatPeople();
ExtraCreatPeople.prototype.data = ;
ExtraCreatPeople.prototype.constructor = ExtraCreatPeople; var someone = new CreatPeople("Tom", , "student");
someone.showInfo(); //Tom 18 student var otherone = new ExtraCreatPeople("Bob", , "student", "Sing");
otherone.showInfo();     //Bob 18 student sing 1

  通过子类原型继承,生成了一个新的构造函数,实现了对于原构造函数的扩展。不过如果仔细看上面的代码,我们就会发现ExtraCreatePeople创建的对象时会调用两次new,这就造成了内存的浪费,同时也影响了效率。上面我们提到过,每一个函数都有一个原型对象,通过原型链由构造函数创建的对象具有原型对象的属性和方法,那么我们将CreatePerson的的原型对象直接借用给ExtraCreatePerson,是不是也可以实现目的呢?

function CreatPeople(name, age, work){
this.name = name;
this.age = age;
this.work = work;
} CreatPeople.prototype.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
str += this[name] + ' ';
}
}
console.log(str);
} function ExtraCreatPeople(name, age, work, hobby){
CreatPeople.apply(this, arguments);
this.hobby = hobby;
}
ExtraCreatPeople.prototype = CreatPeople.prototype;
ExtraCreatPeople.prototype.data = ;
ExtraCreatPeople.prototype.constructor = ExtraCreatPeople; var someone = new CreatPeople("Tom", , "student");
someone.showInfo(); //Tom 18 student 1 var otherone = new ExtraCreatPeople("Bob", , "student", "Sing");
otherone.showInfo();     //Bob 18 student sing 1

  通过借用原型链,也实现了相同的功能,不过仔细观察,就会发现借用原型引入了新的问题,新构造函数会污染原有构造函数的原型链,从而给原构造函数添加了新的属性,这与我们上面提到的在不影响原有对象的基础上创建新构造函数的目的是不符合,在通过对比上面的new引用,我们发现new方式实现的新构造函数并不会污染原有原型链,结合以上两种模式,就实现下面的构造函数创建:

function CreatPeople(name, age, work){
this.name = name;
this.age = age;
this.work = work;
} CreatPeople.prototype.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
str += this[name] + ' ';
}
}
console.log(str);
} function F(){
} F.prototype = CreatPeople.prototype; function ExtraCreatPeople(name, age, work, hobby){
CreatPeople.apply(this, arguments);
this.hobby = hobby;
}
ExtraCreatPeople.prototype = new F();
ExtraCreatPeople.prototype.data = ;
ExtraCreatPeople.prototype.constructor = ExtraCreatPeople; var someone = new CreatPeople("Tom", , "student");
someone.showInfo(); //Tom 18 student var otherone = new ExtraCreatPeople("Bob", , "student", "Sing");
otherone.showInfo();     //Bob 18 student sing 1

  通过中间对象,实现了新构造函数与原构造函数的隔离,不过我们看下面的代码:

function CreatPeople(name, age, work){
this.name = name;
this.age = age;
this.work = work;
} CreatPeople.prototype.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
if(typeof(this[name]) == "object"){
str += this[name].name + ' ';
}else{
str += this[name] + ' ';
}
}
}
console.log(str);
}
CreatPeople.prototype.child = {
name : "Lucy"
} function F(){
} F.prototype = CreatPeople.prototype;
function ExtraCreatPeople(name, age, work, habit){
CreatPeople.apply(this, arguments);
this.habit = habit;
}
ExtraCreatPeople.prototype = new F();
ExtraCreatPeople.prototype.data = ;
ExtraCreatPeople.prototype.constructor = ExtraCreatPeople; var someone = new CreatPeople("Tom", , "student");
someone.showInfo(); //Tom 18 student Lucy var otherone = new ExtraCreatPeople("Bob", , "student", "Sing");
otherone.showInfo();     //Bob 18 student sing 1 Lucy someone.child.name = "pop"; someone.showInfo(); //Tom 18 student pop
otherone.showInfo(); //Bob 18 student sing 1 pop

  在这里,很容易发现someone中对原型链上数据的修改导致otherone中的对应属性也发生了改变,这种错误隐蔽性高,不易发现,因此需要着重理解和掌握!不过通过上述了解,我们发现原型链的借用就是可以理解为对象的复制过程,就原构造函数对象的参数赋值给新的构造函数,同时两个构造函数对象不会互相影响,这里就要理解JS中对象中比较复杂的部分、浅拷贝和深拷贝,具体详见下段:对象的克隆。

3.对象的克隆 

 对象的克隆分为两种方式,浅度克隆:原始类型为值传递,对象类型仍为引用传递。深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。从这两部分可以看出来,上面的原型引用就是浅度克隆,为了对原型继承的要求,深度克隆就满足我们的要求,如下:

function isClass(obj){
if(obj == null) return "NULL";
if(obj == undefined) return "Undefiend";
return Object.prototype.toString.call(obj).slice(, -);
} function deepclone(obj){
var result;
var objClass = isClass(obj);
//确定result的类型
if(objClass==="Object"){
result={};
}else if(objClass==="Array"){
result=[];
}else{
return obj;
}
for(key in obj){
var copy=obj[key];
if(isClass(copy)=="Object"){
result[key]=arguments.callee(copy); //递归调用
}else if(isClass(copy)=="Array"){
result[key]=arguments.callee(copy);
}else{
result[key]=obj[key];
}
}
return result;
} function CreatPeople(name, age, work){
this.name = name;
this.age = age;
this.work = work;
} CreatPeople.prototype.showInfo = function(){
var str = "";
for(var name in this){
if(typeof(this[name]) != "function"){
if(typeof(this[name]) == "object"){
str += this[name].name + ' ';
}else{
str += this[name] + ' ';
}
}
}
console.log(str);
} CreatPeople.prototype.child = {
name : "Lucy"
} function ExtraCreatPeople(name, age, work, habit){
CreatPeople.apply(this, arguments);
this.habit = habit;
} ExtraCreatPeople.prototype = deepclone(CreatPeople.prototype);
ExtraCreatPeople.prototype.data = ;
ExtraCreatPeople.prototype.constructor = ExtraCreatPeople; var someone = new CreatPeople("Tom", , "student");
someone.showInfo(); //Tom 18 student Lucy var otherone = new ExtraCreatPeople("Bob", , "student", "Sing");
otherone.showInfo();     //Bob 18 student sing Lucy 1 someone.child.name = "pop"; someone.showInfo(); //Tom 18 student pop
otherone.showInfo(); //Bob 18 student sing Lucy 1

  到此为止,子类和父类实现了完全的隔离,这也是实现原型继承最佳的方式。

web前端学习(二) javascript对象和原型继承的更多相关文章

  1. web前端学习:JavaScript学习指南

    JavaScript是一种属于网络的脚本语言,已经被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果.通常JavaScript脚本是通过嵌入在HTML中来实现 ...

  2. web前端学习python之第一章_基础语法(二)

    web前端学习python之第一章_基础语法(二) 前言:最近新做了一个管理系统,前端已经基本完成, 但是后端人手不足没人给我写接口,自力更生丰衣足食, 所以决定自学python自己给自己写接口哈哈哈 ...

  3. web前端学习就这9个阶段,你属于哪个阶段?

    第一阶段:HTML+CSS: HTML进阶.CSS进阶.div+css布局.HTML+css整站开发. JavaScript基础:Js基础教程.js内置对象常用方法.常见DOM树操作大全.ECMAsc ...

  4. 腾讯Web前端开发框架JX(Javascript eXtension tools)

    转自:Web前端开发-Web前端工程师 » 腾讯Web前端开发框架JX(Javascript eXtension tools) JX – Javascript eXtension tools 一个类似 ...

  5. Web前端学习攻略

    HTML+CSS: HTML进阶.CSS进阶.div+css布局.HTML+css整站开发. JavaScript基础: Js基础教程.js内置对象常用方法.常见DOM树操作大全.ECMAscript ...

  6. 进击的Python【第十四章】:Web前端基础之Javascript

    进击的Python[第十四章]:Web前端基础之Javascript 一.javascript是什么 JavaScript 是一种轻量级的编程语言. JavaScript 是可插入 HTML 页面的编 ...

  7. 每天成长一点---WEB前端学习入门笔记

    WEB前端学习入门笔记 从今天开始,本人就要学习WEB前端了. 经过老师的建议,说到他每天都会记录下来新的知识点,每天都是在围绕着这些问题来度过,很有必要每天抽出半个小时来写一个知识总结,及时对一天工 ...

  8. 【前端】Web前端学习笔记【2】

    [2016.02.22至今]的学习笔记. 相关博客: Web前端学习笔记[1] 1. this在 JavaScript 中主要有以下五种使用场景 在全局函数调用中,this 绑定全局对象,浏览器环境全 ...

  9. 【前端】Web前端学习笔记【1】

    ... [2015.12.02-2016.02.22]期间的学习笔记. 相关博客: Web前端学习笔记[2] 1. JS中的: (1)continue 语句 (带有或不带标签引用)只能用在循环中. ( ...

随机推荐

  1. 注册Jdbc驱动程序的三种方式

    注册Jdbc驱动程序的三种方式 1. Class.forName("com.mysql.jdbc.Driver"); 2. DriverManager.registerDriver ...

  2. 关于DoesObjectExist

    目录: 我们可以看到这个文件夹目录是存在的 文件: 然后,我们运行测试一下: 文件存在检测成功(正常) 文件夹存在,但检测失败! ??? 明明存在的,为什么检测不到……

  3. 论文阅读(Lukas Neuman——【ICDAR2015】Efficient Scene Text Localization and Recognition with Local Character Refinement)

    Lukas Neuman--[ICDAR2015]Efficient Scene Text Localization and Recognition with Local Character Refi ...

  4. sharepont 2013 隐藏Ribbon 菜单

    引用:C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI\Microsoft.Web.Comma ...

  5. Eclipse快捷键

    http://www.blogjava.net/action/articles/17339.html http://blog.csdn.net/keenweiwei/article/details/3 ...

  6. 下载最新版本的Oracle Database

    直接访问Oracle的官网就可以找到,鉴于Oracle经常改到下载面也我这里直接粘贴下载地址 http://www.oracle.com/technetwork/database/enterprise ...

  7. Java使用DatagramSocket

    转自:http://book.51cto.com/art/201203/322540.htm Java使用DatagramSocket代表UDP协议的Socket,DatagramSocket本身只是 ...

  8. Dynamics AX 2012 R2 业务系列

    在之前的一系列博文里,Reinhard介绍了Dynamics AX Demo的安装与配置.相信同学们看完后,都已经成功拥有了一个测试环境. 众所周知的是,ERP作为一个特殊的软件系统,他有着背后的业务 ...

  9. web项目 log4j2的路径问题

    项目中用到log4j2记录日志,结果运行的时候总也不见log文件的产生. 查看官方文档得知,在web项目中使用log4j2需要加入log4j-web包 log4j2.xml <?xml vers ...

  10. 20145227&20145201 《信息安全系统设计基础》实验五

    北京电子科技学院(BESTI) 实 验 报 告 课程:信息安全系统设计基础 班级:1452 姓名:(按贡献大小排名)鄢曼君 李子璇 学号:(按贡献大小排名)20145227 20145201 成绩: ...