javascript的函数、创建对象、封装、属性和方法、继承


Posted in Javascript onMarch 10, 2011

一,function
从一开始接触到js就感觉好灵活,每个人的写法都不一样,比如一个function就有N种写法
如:function showMsg(){},var showMsg=function(){},showMsg=function(){}
似乎没有什么区别,都是一样的嘛,真的是一样的吗,大家看看下面的例子

///----------------------------------------------------------------------------------------- ------- 
//函数定义:命名函数(声明式),匿名函数(引用式) 
//声明式,定义代码先于函数执行代码被解析 
function t1(){ 
dwn("t1"); 
} 
t1(); 
function t1(){ 
dwn("new t1"); 
} 
t1(); 
//引用式,在函数运行中进行动态解析 
var t1=function(){ 
dwn("new new t1"); 
} 
t1(); 
var t1=function(){ 
dwn("new new new t1"); 
} 
t1(); 
//以上输出:new t1,new t1,new new t1,new new new t1

可能想着应该是输出t1,new t1,new newt1,new new new t1,结果却并不是这样,应该理解这句话:声明

式,定义代码先于函数执行代码被解析
如果深入一步,应该说是scope链问题,实际上前面两个方法等价于window.t1,可以理解为t1是window的

一个公有属性,被赋了两次值,以最后一次赋值为最终值
而后面两个方法,可以理解为是t1是个变量,第四个方法的var去掉之后的结果仍然不会改变
然而,当第四个方法改成function t1(){}这样的声明式时,结果变成了new new new t1,new new new

t1,new new t1,new new t1
前面两个按照我的理解可以很好的理解为什么是这个答案,第三个也可以理解,但是最后一个输出让我比

较纠结,希望有高手出现解答一下
另外匿名函数还有(function(){...})()这样的写法,最后一个括号用于参数输入
还有var t1=new function(){..}这样的声明,实际上t1已经是一个对象了
例:

var t2 = new function() 
{ 
var temp = 100; //私有成员 
this.temp = 200; //公有成员,这两个概念会在第三点以后展开说明 
return temp + this.temp; 
} alert(typeof(t2)); //object 
alert(t2.constructor()); //300 
除此之外,还有使用系统内置函数对象来构建一个函数,例: 
var t3 = new Function('var temp = 100; this.temp = 200; return temp + this.temp;'); //这个位置加不加new结果都一样,WHY 
alert(typeof(t3)); //function 
alert(t3()); //300

二,创建对象
首先我们理解一下面向对象编程(Object-Oriented Programming,OOP),使用OOP技术,常常要使用许多

代码模块,每个模块都提供特定的功能,每个模块都是孤立的,甚至与其它模块完全独立
。这种模块化编程方法提供了非常大的多样性,大大增加了代码的重用机会。可以举例进一步说明这个问

题,假定计算机上的一个高性能应用程序是一辆一流赛车。如果使用传统的编程技巧,这辆赛车就是
一个单元。如果要改进该车,就必须替换整个单元,把它送回厂商,让汽车专家升级它,或者购买一个新

车。如果使用OOP技术,就只需从厂商处购买新的引擎,自己按照说明替换它,而不必用钢锯切割车体。
不过大部分的论点是,javascript并不是直接的面向对象的语言,但是通过模拟可以做到很多面向对象语

言才能做到的事,如继承,多态,封装,javascript都能干(没有做不到,只是想不到)

///----------------------------------------------------------------------------------------- ------- 
//以下三种构造对象的方法 
//new Object,实例化一个Object 
var a=new Object(); 
a.x=1,a.y=2; 
//对象直接量 
var b={x:1,y:2}; 
//定义类型 
function Point(x,y){ //类似于C#中的类 
this.x=x; 
this.y=y; 
} 
var p=new Point(1,2); //实例化类

第一种方法通过构造基本对象直接添加属性的方法来实现,第二种和第一种差不多,可以看成是第一种方

法的快捷表示法
第三种方法中,可以以”类“为基础,创造多个类型相同的对象

三,对象属性的封装(公有和私有)
以例子来说明
function List(){
var m_elements=[]; //私有成员,在对象外无法访问,如果此处无var声明,则m_elements将变成全局变

量,这样外部是可以直接访问到的,如alert(m_elements[0])

m_elements=Array.apply(m_elements,arguments); 
//此处模拟getter,使用时alist.length; 
//等价于getName()方式:this.length=function(){return m_elements.length;},使用时 alist.length(); 
//公有属性,可以通过"."运算符或下标来访问 
this.length={ 
valueOf:function(){ 
return m_elements.length; 
}, 
toString:function(){ 
return m_elements.length; 
} 
} 
//公有方法,此方法使用得alert(alist)相当于alert(alist.toString()) 
this.toString=function(){ 
return m_elements.toString(); 
} 
//公有方法 
this.add=function(){ 
m_elements.push.apply(m_elements,arguments); 
} 
//私有方法如下形式,这里涉及到了闭包的概念,接下来继续说明 
//var add=function()或function add() 
//{ 
//m_elements.push.apply(m_elements,arguments); 
//} 
} 
var alist=new List(1,2,3); 
dwn(alist); //=alert(alist.toString()),输出1,2,3 
dwn(alist.length); //输出3 
alist.add(4,5,6); 
dwn(alist); //输出1,2,3,4,5,6 
dwn(alist.length); //输出6

四,属性和方法的类型
javascript里,对象的属性和方法支持4种不同的类型:private property(私有属性),dynamic public

property(动态公有属性),static public property/prototype property(静态公有属性或原型属性),
static property(静态属性或类属性)。私有属性对外界完全不具备访问性,可以通过内部的getter和

setter(都是模拟);动态公有属性外界可以访问,每个对象实例持有一个副本,不会相互影响;原型
属性每个对象实例共享唯一副本;类属性不作为实例的属性,只作为类的属性。
以下是例子:

///----------------------------------------------------------------------------------------- ------- 
//动态公有类型,静态公有类型(原型属性) 
function myClass(){ 
var p=100; //private property 
this.x=10; //dynamic public property 
} 
myClass.prototype.y=20; //static public property or prototype property,动态为myClass的原型添 
加了属性,将作用于所有实例化了的对象,注意这里用到了prototype,这是一个非常有用的东东 
//要想成为高级javascript阶段,prototype和闭包必须得理解和适当应用 
myClass.z=30; //static property 
var a=new myClass(); 
dwn(a.p) //undefined 
dwn(a.x) //10 
dwn(a.y) //20 
a.x=20; 
a.y=40; 
dwn(a.x); //20 
dwn(a.y); //40 
delete(a.x); //删除对象a的属性x 
delete(a.y); //删除对象a的属性y 
dwn(a.x); //undefined 
dwn(a.y); //20 静态公有属性y被删除后还原为原型属性y 
dwn(a.z); //undefined 类属性无法通过对象访问 
dwn(myClass.z);

五,原型(prototype)
这里只讲部分,prototype和闭包都不是几句话都能讲清楚的,如果这里可以给你一些启蒙,则万幸矣
习语”照猫画虎“,这里的猫就是原型,虎是类型,可以表示成:虎.prototype=某只猫 or

虎.prototype=new 猫()
因为原型属性每个对象实例共享唯一副本,所以当实例中的一个调整了一个原型属性的值时,所有实例调

用这个属性时都将发生变化,这点需要注意
以下是原型关系的类型链:

function ClassA(){ 
} 
ClassA.prototype=new Object(); 
function ClassB(){ 
} 
ClassB.prototype=new ClassA(); 
function ClassC(){ 
} 
ClassC.prototype=new ClassB(); 
var obj=new ClassC(); 
dwn(obj instanceof ClassC); //true 
dwn(obj instanceof ClassB); //true 
dwn(obj instanceof ClassA); //true 
dwn(obj instanceof Object); //true 
带默认值的Point对象: 
function Point2(x,y){ 
if (x) this.x=x; 
if (y) this.y=y; 
} 
//设定Point2对象的x,y默认值为0 
Point2.prototype.x=0; 
Point2.prototype.y=0; 
//p1是一个默认(0,0)的对象 
var p1=new Point2(); //可以写成var p1=new Point2也不会出错,WHY 
//p2赋值 
var p2=new Point2(1,2); 
dwn(p1.x+","+p1.y); //0,0 
dwn(p2.x+","+p2.y); //1,2 
delete对象的属性后,原型属性将回到初始化的状态: 
function ClassD(){ 
this.a=100; 
this.b=200; 
this.c=300 
} 
ClassD.prototype=new ClassD(); //将ClassD原有的属性设为原型,包括其值 
ClassD.prototype.reset=function(){ //将非原型属性删除 
for (var each in this) { 
delete this[each]; 
} 
} 
var d=new ClassD(); 
dwn(d.a); //100 
d.a*=2; 
d.b*=2; 
d.c*=2; 
dwn(d.a); //200 
dwn(d.b); //400 
dwn(d.c); //600 
d.reset(); //删掉非原型属性,所有回来原型 
dwn(d.a); //100 
dwn(d.b); //200 
dwn(d.c); //300

六,继承
如果两个类都是同一个实例的类型,那么它们之间存在着某种关系,我们把同一个实例的类型之间的泛化

关系称为继承。C#和JAVA中都有这个,具体的理解就不说了。
在javascript中,并不直接从方法上支持继承,但是就像前面说的,可以模拟啊
方法可以归纳为四种:构造继承法,原型继承法,实例继承法和拷贝继承法。融会贯通之后,还有混合继

续法,这是什么法,就是前面四种挑几种混着来~
以下例子来源于王者归来,其中涉及到了apply,call和一些Array的用法,有兴趣的可以自己在园子里搜索

一下
1,构造继续法例子:

//定义一个Collection类型 
function Collection(size) 
{ 
this.size = function(){return size}; //公有方法,可以被继承 
} Collection.prototype.isEmpty = function(){ //静态方法,不能被继承 
return this.size() == 0; 
} 
//定义一个ArrayList类型,它"继承"Collection类型 
function ArrayList() 
{ 
var m_elements = []; //私有成员,不能被继承 
m_elements = Array.apply(m_elements, arguments); 
//ArrayList类型继承Collection 
this.base = Collection; 
this.base.call(this, m_elements.length); 
this.add = function() 
{ 
return m_elements.push.apply(m_elements, arguments); 
} 
this.toArray = function() 
{ 
return m_elements; 
} 
} 
ArrayList.prototype.toString = function() 
{ 
return this.toArray().toString(); 
} 
//定义一个SortedList类型,它继承ArrayList类型 
function SortedList() 
{ 
//SortedList类型继承ArrayList 
this.base = ArrayList; 
this.base.apply(this, arguments); 
this.sort = function() 
{ 
var arr = this.toArray(); 
arr.sort.apply(arr, arguments); 
} 
} 
//构造一个ArrayList 
var a = new ArrayList(1,2,3); 
dwn(a); 
dwn(a.size()); //a从Collection继承了size()方法 
dwn(a.isEmpty); //但是a没有继承到isEmpty()方法 
//构造一个SortedList 
var b = new SortedList(3,1,2); 
b.add(4,0); //b 从ArrayList继承了add()方法 
dwn(b.toArray()); //b 从ArrayList继承了toArray()方法 
b.sort(); //b 自己实现的sort()方法 
dwn(b.toArray()); 
dwn(b); 
dwn(b.size()); //b从Collection继承了size()方法

2,原型继承法例子:
//定义一个Point类型 
function Point(dimension) 
{ this.dimension = dimension; 
} 
//定义一个Point2D类型,"继承"Point类型 
function Point2D(x, y) 
{ 
this.x = x; 
this.y = y; 
} 
Point2D.prototype.distance = function() 
{ 
return Math.sqrt(this.x * this.x + this.y * this.y); 
} 
Point2D.prototype = new Point(2); //Point2D继承了Point 
//定义一个Point3D类型,也继承Point类型 
function Point3D(x, y, z) 
{ 
this.x = x; 
this.y = y; 
this.z = z; 
} 
Point3D.prototype = new Point(3); //Point3D也继承了Point 
//构造一个Point2D对象 
var p1 = new Point2D(0,0); 
//构造一个Point3D对象 
var p2 = new Point3D(0,1,2); 
dwn(p1.dimension); 
dwn(p2.dimension); 
dwn(p1 instanceof Point2D); //p1 是一个 Point2D 
dwn(p1 instanceof Point); //p1 也是一个 Point 
dwn(p2 instanceof Point); //p2 是一个Point

以上两种方法是最常用的
3,实例继承法例子:
在说此法例子之前,说说构造继承法的局限,如下:
function MyDate() 
{ 
this.base = Date; 
this.base.apply(this, arguments); 
} 
var date = new MyDate(); 
alert(date.toGMTString); //undefined,date并没有继承到Date类型,所以没有toGMTString方法

核心对象的某些方法不能被构造继承,原因是核心对象并不像我们自定义的一般对象那样在构造函数里进

行赋值或初始化操作
换成原型继承法呢?,如下:

function MyDate(){} 
MyDate.prototype=new Date(); 
var date=new MyDate(); 
alert(date.toGMTString); //'[object]'不是日期对象,仍然没有继承到Date类型!

现在,换成实例继承法:
function MyDate() 
{ 
var instance = new Date(); //instance是一个新创建的日期对象 
instance.printDate = function(){ 
document.write("<p> "+instance.toLocaleString()+"</p> "); 
} //对instance扩展printDate()方法 
return instance; //将instance作为构造函数的返回值返回 
} 
var myDate = new MyDate(); 
dwn(myDate.toGMTString()); //这回成功输出了正确的时间字符串,看来myDate已经是一个Date的实例

了,继承成功
myDate.printDate(); //如果没有return instance,将不能以下标访问,因为是私有对象的方法
4,拷贝继承法例子:
Function.prototype.extends = function(obj) 
{ 
for(var each in obj) 
{ 
this.prototype[each] = obj[each]; 
//对对象的属性进行一对一的复制,但是它又慢又容易引起问题 
//所以这种“继承”方式一般不推荐使用 
} 
} 
var Point2D = function(){ 
//…… 
} 
Point2D.extends(new Point()) 
{ 
//…… 
}

这种继承法似乎是用得很少的。
5,混合继承例子:
function Point2D(x, y) 
{ 
this.x = x; 
this.y = y; 
} 
function ColorPoint2D(x, y, c) 
{ 
Point2D.call(this, x, y); //这里是构造继承,调用了父类的构造函数 
//从前面的例子看过来,这里等价于 
//this.base=Point2D; 
//this.base.call(this,x,y); 
this.color = c; 
} 
ColorPoint2D.prototype = new Point2D(); //这里用了原型继承,让ColorPoint2D以Point2D对象为原型
Javascript 相关文章推荐
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
Mar 09 Javascript
Textbox控件注册回车事件及触发按钮提交事件具体实现
Mar 04 Javascript
为Javascript中的String对象添加去除左右空格的方法(示例代码)
Nov 30 Javascript
js 异步操作回调函数如何控制执行顺序
Dec 24 Javascript
js中精确计算加法和减法示例
Mar 28 Javascript
html的DOM中Event对象onblur事件用法实例
Jan 21 Javascript
js实现可兼容IE、FF、Chrome、Opera及Safari的音乐播放器
Feb 11 Javascript
Node.js的MongoDB驱动Mongoose基本使用教程
Mar 01 Javascript
基于BootStrap Metronic开发框架经验小结【七】数据的导入、导出及附件的查看处理
May 12 Javascript
微信小程序 触控事件详细介绍
Oct 17 Javascript
jQuery中的select操作详解
Nov 29 Javascript
vue fetch中的.then()的正确使用方法
Apr 17 Javascript
在jQuery 1.5中使用deferred对象的代码(翻译)
Mar 10 #Javascript
基于Jquery的跨域传输数据(JSONP)
Mar 10 #Javascript
jQuery.autocomplete 支持中文输入(firefox)修正方法
Mar 10 #Javascript
Jquery中getJSON在asp.net中的使用说明
Mar 10 #Javascript
JQuery中的$.getJSON 使用说明
Mar 10 #Javascript
基于jquery的地址栏射击游戏代码
Mar 10 #Javascript
基于jquery的无缝循环新闻列表插件
Mar 07 #Javascript
You might like
php时间不正确的解决方法
2008/04/09 PHP
php学习笔记 面向对象的构造与析构方法
2011/06/13 PHP
PHP使用SOAP调用.net的WebService数据
2013/11/12 PHP
PHP人民币金额转大写实例代码
2015/10/02 PHP
YII Framework框架教程之安全方案详解
2016/03/14 PHP
静态页面的值传递(三部曲)
2006/09/25 Javascript
IE FF OPERA都可用的弹出层实现代码
2009/09/29 Javascript
JQuery上传插件Uploadify使用详解及错误处理
2010/04/27 Javascript
用javascript添加控件自定义属性解析
2013/11/25 Javascript
jquery日历控件实现方法分享
2014/03/07 Javascript
jquery得到iframe src属性值的方法
2014/09/25 Javascript
jQuery绑定事件监听bind和移除事件监听unbind用法实例详解
2016/01/19 Javascript
js检查是否关闭浏览器的方法
2016/08/02 Javascript
JavaScript实现汉字转换为拼音的库文件示例
2016/12/22 Javascript
十分钟带你快速了解React16新特性
2017/11/10 Javascript
对vue下点击事件传参和不传参的区别详解
2018/09/15 Javascript
node.JS路径解析之PATH模块使用方法详解
2020/02/06 Javascript
pymssql ntext字段调用问题解决方法
2008/12/17 Python
详解django自定义中间件处理
2018/11/21 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
在pytorch中为Module和Tensor指定GPU的例子
2019/08/19 Python
SELENIUM自动化模拟键盘快捷键操作实现解析
2019/10/28 Python
numpy ndarray 取出满足特定条件的某些行实例
2019/12/05 Python
python库skimage给灰度图像染色的方法示例
2020/04/27 Python
python 实现IP子网计算
2021/02/18 Python
Grow Gorgeous美国官网:只要八天,体验唤醒毛囊后新生的茂密秀发
2018/06/04 全球购物
蹦床仓库:Trampoline Warehouse
2018/12/06 全球购物
说说你所熟悉或听说过的j2ee中的几种常用模式?及对设计模式的一些看法
2012/05/24 面试题
世界经理人咨询有限公司面试
2014/09/23 面试题
关于期中考试的反思
2014/02/02 职场文书
连锁超市项目计划书
2014/09/15 职场文书
“四风”问题对照检查材料思想汇报
2014/09/16 职场文书
刑事辩护授权委托书格式
2014/10/13 职场文书
2015庆祝七一建党节94周年活动总结
2015/03/20 职场文书
观后感的写法
2015/06/19 职场文书
党风廉政建设心得体会
2019/05/21 职场文书