读jQuery源码时候,我常想到底那些因素会让我读不懂代码,其中最关键的是哪个,最早觉得是jQuery的架构设计,当我查阅资料终于找到jQuery架构设计的入口时候,我发现javascript基础语法的熟练运用才是读源码的关键,因此现在把javascript基础知识系统回顾下很有必要,而且jQuery源码的研究就是对javascript基础知识的加深和灵活运用,我想后面临摹jQuery将和我对javascript基础知识的学习穿插起来,这样一定会对各种疑难问题有更好的解答。
最近深入学习javascript后,有个体会:面向对象的方式编程才是高效灵活的编程,也是现在唯一可以让代码更加健壮的编程方式。如果我们抛开那些玄乎的抽象出类等等思想,我自己对面向对象的从写程序的角度理解就是:复用和封装。复用具体就是让你尽量少写重复代码,封装就是将一些耦合度很高的逻辑放到一个程序块里,而且尽量让里面内容不受外界影响。最后的结论是:优秀的javascript代码都是面向对象的。
今天要讲的是如何构建javascript对象。
ECMA-262对对象的定义是:无序属性的集合,其属性可以包含基本值、对象或函数。javascript的对象其实就是java里的map,即键值对。
在javascript创建一个对象一共有三种方式:
方式一:通过Object对象
方式二:通过构造函数
方式三:对象初始化
1.通过Object对象来构建对象,代码如下:
//直接使用Object创建对象
var obj = new Object();
obj.id = '001';
obj.name = 'My name is obj';
obj.teststring = 'Test obj';
obj.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
obj.sayHello();//id:001@!@name:My name is obj@!@teststring:Test obj
obj['sayHello']();//id:001@!@name:My name is obj@!@teststring:Test obj
var str = 'sayHello';
obj[str]();//id:001@!@name:My name is obj@!@teststring:Test obj
(注意:我这里使用了两种访问对象属性的方式,一种是点运算符,一种是方括号运算符,二者是等价的,但是方括号运算似乎要更强大些,方括号里面我们可以放置变量)
这是最常用,最直观的一种创建对象方法,但是它的缺点太明显了,就是代码复用度很低,我们想到一个对象就创建一个对象,如是就会造成大量的重复代码,因此,javascript程序员将工厂模式引入到了javascrip编程里,请大家看下面的代码:
// 用工厂模式创建对象
function createObj(id,name,teststring)
{
var o = new Object();
o.id = id;
o.name = name;
o.teststring = teststring;
o.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
return o;
}
var obj = createObj('002','My Name is obj2','Test Obj2');
obj.sayHello();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2
obj['sayHello']();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2
var str = 'sayHello';
obj[str]();//id:002@!@name:My Name is obj2@!@teststring:Test Obj2
工厂模式解决了创建相似对象的问题,如果抛开它构造对象的对象识别问题,工厂模式挺完美的,如果你做的javascript应用不是太复杂,建议使用工厂模式构造对象,这种写法可读性很高。(写到工厂模式,我在临摹jQuery里面有段注解似乎不太正确,这个以后要修正)。
2.通过构造函数
在我前面的博文《javascript笔记:javascript前世续篇(从javascript起源谈下它的继承) 》里面我从javascript的起源里谈到了javascript面向对象的一些设计思想,其中就有关于javascript构造函数的设计。几乎所有使用构造函数方式构建对象都会使用到new运算符,javascript里面的构造函数比较特别的,在javascript里没有类的概念,new 后面跟的直接是构造函数,大家看下面的代码:
// 使用构造函数创建对象
function Obj(id1,name1,teststring1)
{
this.id = id1;
this.name = name1;
this.teststring = teststring1;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var obj = new Obj('003','My Name is obj3','Test Obj3');
obj.sayHello();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3
obj['sayHello']();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3
var str = 'sayHello';
obj[str]();//id:003@!@name:My Name is obj3@!@teststring:Test Obj3
构造函数式和工厂模式从代码角度而言很像,我在学习javascript初期,单独看一种方式,思维总是惯性的把二者混为一谈,如果两个放在一起还是觉得有差异,主要是javascript里面function被赋予的功能太多,如果在一个大型程序里面二者交替使用,不晕头才怪了。其实通过两者构造对象的不同,我可以把function的使用分为构造函数式和函数式。下面我将重点分析下两种方式,这里的见底或许不全面,要是哪位高手看到了可以补充和指点哈。
首先我去掉方法里各个属性的this指针,而sayHello里面引用的this指针不去掉。代码如下:
// 深入分析构造函数1
function Obj(id1,name1,teststring1)
{
id = id1;
name = name1;
teststring = teststring1;
sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var obj = new Obj('004','My Name is obj4','Test Obj4');
sayHello();//id:undefined@!@name:@!@teststring:undefined
window.sayHello();//id:undefined@!@name:@!@teststring:undefined
obj.sayHello();//obj.sayHello is not a function [在此错误处中断] obj.sayHello();
(纠正:sayHello();和window.sayHello()结果是id:004@!@name:My Name is obj4@!@teststring:Test Obj4,很抱歉,下面的一些分析也存在一些问题,为了保证本文完整性,这里我只做纠正了,在下篇文章开篇我会着重分析错误原因)
this永远指向obj的,而sayHello方法里的this.id等等属性的值为undefined,表明Obj的function对象没有id,name,teststring属性,就连sayHello方法在Obj里面也没有定义好,但是直接sayHello();可以找到sayHello方法,最后我们使用window.sayHello();才知道sayHello是被定义在window里面了。如是我去掉Obj里面所有this,代码如下:
// 深入分析构造函数2
function Obj(id1,name1,teststring1)
{
id = id1;
name = name1;
teststring = teststring1;
sayHello = function()
{
console.log('id:' + id + '@!@name:' + name + '@!@teststring:' + teststring);
}
}
var obj = new Obj('005','My Name is obj5','Test Obj5');
sayHello();//id:005@!@name:My Name is obj5@!@teststring:Test Obj5
window.sayHello();//id:005@!@name:My Name is obj5@!@teststring:Test Obj5
console.log(id);//005
console.log(name);//My Name is obj5
console.log(teststring);//Test Obj5
console.log(window.id);//005
console.log(window.name);//My Name is obj5
console.log(window.teststring);//Test Obj5
由上面内容我得出了下面的结论:
一.javascript是可以做面向对象编程的,我们不能把它当做面向过程的语言;
二.javascript里面对象的创建是特别的,特别在于它和传统的面向对象语言比较起来做了简化,简化到直接使用构造函数来创建对象;
三.function在javascript里面既可以当做函数式使用,又可以作为构造函数的标示(你也可以直接当做类来看待),而区别构造函数式和函数式的区别就是new;
四.如果我们用到了构造函数式才创建对象,那么这里和其他面向对象语言一样,也是有封装的,换种说法是里面定义的属性或者方法是属于该对象的,而让其属于该对象的方式就是用this指针,否则属性和方法将属于window对象。
如果我们不用new运算符,直接使用函数,例如下面代码:
// 深入分析函数式1
function Obj(id1,name1,teststring1)
{
this.id = id1;
this.name = name1;
this.teststring = teststring1;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
Obj('006','My Name is obj6','Test Obj6');
sayHello();//id:006@!@name:My Name is obj6@!@teststring:Test Obj6
window.sayHello();//id:006@!@name:My Name is obj6@!@teststring:Test Obj6
console.log(id);//006
console.log(name);//My Name is obj6
console.log(teststring);//Test Obj6
console.log(window.id);//006
console.log(window.name);//My Name is obj6
console.log(window.teststring);//Test Obj6
直接调用function,this指针都是指向window,也就是全局对象,我以前看到过一句话:不论哪里直接调用函数,里面的this都是指向全局的。这个不论哪里直接调用函数就有学问了啊,看下面代码:
// 深入分析函数式 2
function OuterObj(id1,name1,teststring1)
{
this.id = id1;
this.name = name1;
this.teststring = teststring1;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
function InnerObj(id2,name2,teststring2)
{
this.id = id2;
this.name = name2;
this.teststring = teststring2;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
var innerVal = new InnerObj('101','InnerObj','Test InnerObj');//true
console.log(innerVal instanceof InnerObj);
innerVal.sayHello();//id:101@!@name:InnerObj@!@teststring:Test InnerObj
InnerObj('102','InnerObj0','Test InnerObj0');
}
var outObj = new OuterObj('007','My Name is obj7','Test Obj7');
outObj.sayHello();//id:007@!@name:My Name is obj7@!@teststring:Test Obj7
sayHello();//
window.sayHello();//id:102@!@name:InnerObj0@!@teststring:Test InnerObj0
console.log(id);//102
console.log(name);//InnerObj0
console.log(teststring);//Test InnerObj0
由此可见只要是函数调用this指向的方法和函数都是指向window的,即全局对象。
3.对象初始化
对象初始化方式在有些书上也叫字面量方式构建对象,但是我更喜欢对象初始化方式,这样更直观,代码如下:
// 对象初始化
var obj = {
id:'008',
name:'My Name is obj8',
teststring:'Test Obj8',
sayHello:function(){
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
};
obj.sayHello();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
obj['sayHello']();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
var str = 'sayHello';
obj[str]();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
这种方式是我比较喜欢的一种构建对象的方式,有位javascript大师级的人物曾经建议构建空对象,最好是var obj = {},这句话就表明var obj = {}和var obj = new Object();是等价的。var obj = {}方式更加简洁,避免了o.id;o.name等等繁琐的写法,jQuery源码里面大量使用这样的构造对象的方式。
以上就是我熟知的三种在javascript里面构建对象的方式。下面我将要换个角度来理解javascript构建对象的知识。首先看一段java的代码:
public class Obj {
public static String staticParams = "静态属性,它是属于类的";
private String objId = "编号是对象私有的";
public String objName = "名称是对象公有的";
//构造函数
public Obj(){}
}
javascript对象的属性或方法也可以使用java里的思想分为:属于类的属性和方法,属于对象的属性或方法,还有公有属性和方法以及私有属性和方法。
一.属于类的属性和方法:用对象初始化的方式都可以当做是属于类的属性和方法,这种定义在jQuery里面大量运用;
二.属于对象的属性或方法:用构造函数的方式构建对象,里面用this指针指向的属性和方法都是属于对象的;
三.公有属性和方法:javascript里面属性和方法天生就是公有的;
四.私有属性和方法:这个在javascript里面要通过模拟才能实现,这种模拟一般是使用作用域的原理,比如:在一个function内部用var来定义对象,对象作用域属于改function内部,那么在函数外部是不能访问的,这就是私有变量和方法了。
以上对象的创建,里面的属性和方法操作都是对象专有的,用相同方式构建的类似对象不能做到信息的共享,那如何才能让类似的对象能共享信息了,这就的使用prototype原型链了。
在javascript里面每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途包含可以由特定类型所有实例共享的属性和方法。
代码如下:
//原型模式
function Obj(id1,name1,teststring1)
{
this.id = id1;
this.name = name1;
this.teststring = teststring1;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
Obj.prototype.objflag = '自建的Obj对象';
Obj.prototype.proSayHello = function()
{
console.log('Hello World and Obj');
}
var obj1 = new Obj('008','My Name is obj8','Test Obj8');
var obj2 = new Obj('009','My Name is obj9','Test Obj9');
obj1.sayHello();//id:008@!@name:My Name is obj8@!@teststring:Test Obj8
obj2.sayHello();//id:009@!@name:My Name is obj9@!@teststring:Test Obj9
obj1.proSayHello();//Hello World and Obj
obj2.proSayHello();//Hello World and Obj
console.log(obj1.objflag);//自建的Obj对象
console.log(obj2.objflag);//自建的Obj对象
prototype写起来太繁琐了,而且又不好记,一般许多实例公用的属性和方法都是固定的不容易改变了,那么我们可以用初始化对象的方式来写原生链,这个思路我是从jQuery里学到的,代码如下:
//简化的原型模式
function Obj(id1,name1,teststring1)
{
this.id = id1;
this.name = name1;
this.teststring = teststring1;
this.sayHello = function()
{
console.log('id:' + this.id + '@!@name:' + this.name + '@!@teststring:' + this.teststring);
}
}
Obj.prototype = {
objflag:'自建的Obj对象',
proSayHello:function(){
console.log('Hello World and Obj');
}
};
var obj1 = new Obj('010','My Name is obj10','Test Obj10');
var obj2 = new Obj('011','My Name is obj11','Test Obj11');
obj1.sayHello();//id:010@!@name:My Name is obj10@!@teststring:Test Obj10
obj2.sayHello();//id:011@!@name:My Name is obj11@!@teststring:Test Obj11
obj1.proSayHello();//Hello World and Obj
obj2.proSayHello();//Hello World and Obj
console.log(obj1.objflag);//自建的Obj对象
console.log(obj2.objflag);//自建的Obj对象
好了,这个主题的上半部分写完了,上半部分主要从使用和概念讲起,下半部分我将分析一些原理以及对一些古怪现象的解释。
相关推荐
这份“前端开发必备JavaScript(含源码课件笔记总结)”的资源集合是前端开发者不可多得的学习材料,包含了丰富的知识内容,旨在帮助你深入理解和掌握JavaScript。 一、JavaScript基础 在JavaScript的学习中,首先...
4. JavaScript: JavaScript是网页动态效果的关键,它在客户端运行,处理用户交互。学习JavaScript,你需要掌握变量、函数、对象、DOM操作以及事件处理。JavaScript还有许多库和框架,如jQuery、React和Vue.js,...
理解这些基础知识是掌握JavaScript的第一步,随着学习的深入,还将涉及DOM操作、事件处理、函数、对象、数组、正则表达式、闭包、异步编程等更多概念。JavaScript的灵活性和广泛应用使其成为Web开发不可或缺的一部分...
在本篇【读书笔记: JavaWeb从入门到精通 第13章: Ajax 技术】中,我们将深入探讨Ajax(Asynchronous JavaScript and XML)技术,它是现代Web开发中不可或缺的一部分,用于实现页面的异步更新,提升用户体验。...
通过分析和运行这些例子,可以加深对JavaScript的理解,例如如何创建动态效果、实现表单验证、处理API请求等。 8. **前端框架**:现代Web开发中,JavaScript还用于构建复杂的前端应用,如React、Vue.js和Angular等...
在"JavaScript基础语法.pdf"文件中,这些内容可能以更详细的形式呈现,包括示例代码、运行结果的截图以及深入的解释和分析。 通过深入学习这些基础语法,你可以逐步建立起JavaScript编程的基本技能,为进阶学习和...
JavaScript是一种广泛应用于网页和互联网应用的脚本语言,它的主要任务是增强用户的交互...通过深入理解JavaScript和Julia,以及如何在Pluto环境中整合这两种语言,开发者可以提升自己的技能,创造出更富创新性的项目。
对象是键值对的集合,可以使用对象字面量或构造函数创建。理解原型和原型链对于深入学习JavaScript至关重要。 3. **DOM操作**: Document Object Model(DOM)是HTML和XML文档的结构化表示,JavaScript通过DOM API...
这篇"javascript学习笔记"可能涵盖了JavaScript的基础语法、函数、对象、DOM操作、AJAX以及一些高级特性。 首先,JavaScript语法是基于ECMAScript标准的,包括变量声明(var、let、const)、数据类型(如字符串、...
通过分析和修改源代码,学习者可以深入了解JavaScript面向对象编程、事件处理、以及如何用纯JavaScript实现复杂的逻辑。这个项目对于提升JavaScript编程能力,特别是游戏开发方面的能力,具有相当大的价值。
在前端开发中,让元素在页面上居中是一项常见的任务,尤其对于布局设计至关重要。本篇文章将深入探讨如何使用HTML和JavaScript...通过阅读和分析这些笔记,你可以更深入地理解这些方法,并可能发现其他实用的技巧。
这份名为“JavaScript必看全面总结.zip”的压缩包文件包含了一份深入的JavaScript学习笔记,旨在帮助开发者全面掌握这一动态类型的脚本语言。以下是根据标题和描述提炼出的JavaScript关键知识点: 1. **基础语法**...
“IJavascript是用于Jupyter笔记本的JavaScript内核”这个主题揭示了一个关键的信息——JavaScript现在...通过深入理解和使用IJavaScript,开发者和分析师可以更好地融合JavaScript和数据分析世界,推动创新和发现。
### JavaScript学习笔记:深入理解鼠标滚轮事件与页面加载事件 #### 鼠标滚轮事件的捕获与控制 在网页开发中,鼠标滚轮事件的处理是提升用户体验的一个重要方面,尤其是在需要平滑滚动或缩放操作的场景下。在给定...
在创建对象和数组时,使用直接量(literal)的方法是最快的,尤其是当对象或数组较大时更为明显。延迟加载和条件预加载可以避免不必要的工作,提高性能。 第九章:构建并部署高性能JavaScript应用 为了优化Web应用...
### JavaScript高级第04天笔记1:正则表达式与网络协议 #### 一、正则表达式的概念与使用 ##### 1.1 正则表达式的定义 正则表达式(Regular Expression)是一种用于匹配字符串中字符组合的工具,在 JavaScript 中...
这份"学习笔记:年、日、月,周访问量统计"提供了一个实际的案例,帮助我们理解如何收集、分析并解读这些数据。下面,我们将深入探讨相关知识点。 1. **访问量(Page Views)**:访问量是指用户在网站上打开一个...
《JavaScript忍者秘籍(第2版)》是JavaScript编程领域的一本经典之作,它深入浅出地介绍了JavaScript的核心概念和技术。这本书不仅包含了基础语法,还涵盖了高级特性,旨在帮助读者成为JavaScript的高手,即“忍者...
总的来说,Laverna作为一个JavaScript笔记应用,结合了Markdown编辑器的便利性和本地加密的安全性,为用户提供了私密且高效的笔记管理工具。它的开源特性鼓励了社区参与和创新,有助于软件的持续发展。无论是日常...