目录

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. JSP以及JSP解析原理

    什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写htm ...

  2. jQuery的13个优点

    1.轻量级 JQuery非常轻巧,采用Dean Edwards编写的Packer压缩后,大小不到30KB,如果使用Min版并且在服务器端启用Gzip压缩后,大小只有18KB. gzip: 每天一个li ...

  3. JdbcUtils.java

    package com.jdbc.dbutils; import java.lang.reflect.Field; import java.sql.Connection; import java.sq ...

  4. C#调用windows API的一些方法

    使用C#调用windows API(从其它地方总结来的,以备查询) C#调用windows API也可以叫做C#如何直接调用非托管代码,通常有2种方法: 1.  直接调用从 DLL 导出的函数. 2. ...

  5. 在执行Java命令或eclipse启动程序,提示报错’jvm.cfg无法找到’的解决办法

    一.问题背景 昨天debug代码的时候,突然发现无法启动程序了.每次启动程序的时候均报如下错误:(回家以后重现了下这个问题.发现不同电脑,所在的lib下的文件夹不一样,应该和jdk安装时硬件的情况有关 ...

  6. Python中的传值和引用

    我写这个主要是给自己看,内容也就是便于自己理解,可能会不正确,但目前来看代码测试的结果是对的. python中一切皆对象. 当我们赋值时: a = 1 其实是先创建了一个整数常量1(也是一个对象,且已 ...

  7. 夺命雷公狗-----React_native---5---初步读懂代码模式

    我们的代码一般导出会用两种方式,如下所示: 这两种方法都是可以的.... 引入方式其实也是很简单的,如下所示: 这样即可...

  8. HttpEntity转换Inputstream(红色)加XmlPull解析

    package com.bawei.xml; import java.io.IOException; import java.io.InputStream; import java.util.Arra ...

  9. Oracle Contact By的使用

    1.概述 Oracle “CONNECT BY”是层次查询子句,一般用于树状或者层次结果集的查询 2.使用方式 2.1.通过Connect by 生成序列 Oracle 构造一个月份的天数 ) s_d ...

  10. .NET工程师技术进阶

    通常,一个人对技术的掌握程度可以分为精通.熟练.熟悉.了解,详细解析如下: 精通:能够掌握此技术的85%技术要点以上,使用此技术时间超过两年,并使用此技术成功实施5个以上的项目.能使用此技术优化性能或 ...