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 相关文章推荐
js资料toString 方法
Mar 13 Javascript
JavaScript 函数调用规则
Sep 14 Javascript
javascript 异步页面查询实现代码(asp.net)
May 26 Javascript
jquery解决图片路径不存在执行替换路径
Feb 06 Javascript
JQuery弹出炫丽对话框的同时让背景变灰色
May 22 Javascript
浅谈Sticky组件的改进实现
Mar 22 Javascript
jquery编写Tab选项卡滚动导航切换特效
Jul 17 Javascript
javascript时间戳和日期字符串相互转换代码(超简单)
Jun 22 Javascript
Node.js下自定义错误类型详解
Oct 17 Javascript
Hexo已经看腻了,来手把手教你使用VuePress搭建个人博客
Apr 26 Javascript
微信小程序自定义prompt组件步骤详解
Jun 12 Javascript
vue键盘事件点击事件加native操作
Jul 27 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迅雷、快车、旋风下载专用链转换代码
2010/06/15 PHP
php生成图片验证码的实例讲解
2015/08/03 PHP
HR vs CL BO3 第一场 2.13
2021/03/10 DOTA
关于恒等于(===)和非恒等于(!==)
2007/08/20 Javascript
用Javascript同时提交多个Web表单的方法
2009/12/26 Javascript
JavaScript 基础篇(一)
2012/03/30 Javascript
javascript提取URL的搜索字符串中的参数(自定义函数实现)
2013/01/22 Javascript
js 程序执行与顺序实现详解
2013/05/13 Javascript
JavaScript实现GriwView单列全选(自写代码)
2013/05/13 Javascript
js中opener与parent的区别详细解析
2014/01/14 Javascript
javascript实现行拖动的方法
2015/05/27 Javascript
谈谈JavaScript中function多重理解
2015/08/28 Javascript
用JavaScript实现让浏览器停止载入页面的方法
2017/01/19 Javascript
node.js 发布订阅模式的实例
2017/09/10 Javascript
JS实现图片放大镜插件详解
2017/11/06 Javascript
JQuery特殊效果和链式调用操作示例
2019/05/13 jQuery
layui前端时间戳转化实例
2019/11/15 Javascript
微信小程序学习总结(三)条件、模板、文件引用实例分析
2020/06/04 Javascript
vue调用本地摄像头实现拍照功能
2020/08/14 Javascript
用Python编程实现语音控制电脑
2014/04/01 Python
Django中数据库的数据关系:一对一,一对多,多对多
2018/10/21 Python
Python with关键字,上下文管理器,@contextmanager文件操作示例
2019/10/17 Python
Python使用Tkinter实现滚动抽奖器效果
2020/01/06 Python
Python pip使用超时问题解决方案
2020/08/03 Python
Python实现Kerberos用户的增删改查操作
2020/12/14 Python
pytorch 计算Parameter和FLOP的操作
2021/03/04 Python
生产班组长岗位职责
2014/01/05 职场文书
小学家长会邀请函
2014/01/23 职场文书
担保书怎么写
2014/04/01 职场文书
超市活动计划书
2014/04/24 职场文书
室内设计专业自荐信
2014/05/31 职场文书
法人授权委托书范本
2014/09/17 职场文书
党员个人党性分析材料
2014/12/18 职场文书
申报材料格式
2014/12/30 职场文书
男方婚礼答谢词
2015/01/20 职场文书
2015年后备干部工作总结
2015/05/15 职场文书