目录

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. 基于SSM的分页

    现在基本每一个项目都有用到分页,SSM也是当前企业用到的比较频繁的框架,这里我就总结一下基于SSM的分页: 一.首先我们要准备一个分页的工具类 /** * 分页 */ public class Pag ...

  2. objective-c第七章课后练习3

    题:Fraction类对负分数适用吗?例如:1/4-1/2 能否显示成-1/4? //--------类定义实现参考上篇随笔,此处需更改print方法和main主方法部分---------- - (v ...

  3. js 复选框 全选都选 如果某一个子复选框没选中 则全选按钮不选中

    <!DOCTYPE HTML> <html> <head> <meta charset=UTF-8> <title>js 复选框 全选都选 ...

  4. Linux Socket编程(不限Linux)【转】

    转自:http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html “一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几 ...

  5. oracle 查询最近执行过的 SQL语句(转载)

    oracle 查询最近执行过的 SQL语句 (2014-06-09 18:02:43) 转载▼   分类: Database oracle 查询最近执行过的 SQL语句 select sql_text ...

  6. Prince2七大主题之风险

    Prince2七大主题之风险   我们前几个节学习了PRINCE2七大主题的商业论证.组织.质量和计划,今天我们开展对于风险模块的讲解. 风险:目的是识别.评估和控制不确定性,从而提高项目的成功率.P ...

  7. EPSON LQ610K 设置税控盘打印发票的格式

    问题困扰 之前一直是手动调试发票打印格式,浪费发票纸张不说,而且还浪费时间.今天在Parrells Desktop里利用Bonjour设置打印机的时候,找到了EPSON网站有这方面的介绍,根据上面的提 ...

  8. Sublime Text 3使用指南(1)——安装package control组件

    按Ctrl+`, 调出console 控制台中粘贴一下代码: import urllib.request,os; pf = 'Package Control.sublime-package'; ipp ...

  9. Mac > 编写跨平台桌面应用开发工具,基于 Web 技术

    Electron: The Electron framework lets you write cross-platform desktop applications using JavaScript ...

  10. java 内核

    摘自:http://www.cubrid.org/blog/tags/Java/