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 相关文章推荐
IE innerHTML,outerHTML所引起的问题
Jun 04 Javascript
jQuery仿360导航页图标拖动排序效果代码分享
Aug 24 Javascript
jQuery mobile 移动web(6)
Dec 20 Javascript
JS中如何比较两个Json对象是否相等实例代码
Jul 13 Javascript
jQuery为动态生成的select元素添加事件的方法
Aug 29 Javascript
Vue.js框架路由使用方法实例详解
Aug 25 Javascript
Javascript中从学习bind到实现bind的过程
Jan 05 Javascript
JS实现的抛物线运动效果示例
Jan 30 Javascript
jsonp跨域获取数据的基础教程
Jul 01 Javascript
解决ng-repeat产生的ng-model中取不到值的问题
Oct 02 Javascript
jquery实现吸顶导航效果
Jan 08 jQuery
微信小程序图片自适应实现解析
Jan 21 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集成FCK的函数代码
2008/09/27 PHP
浅析php中三个等号(===)和两个等号(==)的区别
2013/08/06 PHP
php+ajax实现无刷新的新闻留言系统
2020/12/21 PHP
PHP获取昨天、今天及明天日期的方法
2016/02/03 PHP
使用onbeforeunload属性后的副作用
2007/03/08 Javascript
JavaScript 操作键盘的Enter事件(键盘任何事件),兼容多浏览器
2010/10/11 Javascript
常用一些Javascript判断函数
2012/08/14 Javascript
JQuery的read函数与js的onload不同方式实现
2013/03/18 Javascript
轻松创建nodejs服务器(10):处理上传图片
2014/12/18 NodeJs
Nodejs学习笔记之入门篇
2015/04/16 NodeJs
JavaScript数组和循环详解
2015/04/27 Javascript
Bootstrap所支持的表单控件实例详解
2016/05/16 Javascript
JavaScript 对象详细整理总结
2016/09/29 Javascript
JS中substring与substr的用法
2016/11/16 Javascript
JS滚动到指定位置导航栏固定顶部
2017/07/03 Javascript
JS判断微信扫码的方法
2017/08/07 Javascript
Vue filter格式化时间戳时间成标准日期格式的方法
2018/09/16 Javascript
Vue中使用Lodop插件实现打印功能的简单方法
2019/12/19 Javascript
js实现适配移动端的拖动效果
2020/01/13 Javascript
axios解决高并发的方法:axios.all()与axios.spread()的操作
2020/11/09 Javascript
Python实现读取文件最后n行的方法
2017/02/23 Python
Python实现二维数组输出为图片
2018/04/03 Python
Python3.5面向对象编程图文与实例详解
2019/04/24 Python
详解如何用python实现一个简单下载器的服务端和客户端
2019/10/28 Python
利用Python脚本实现自动刷网课
2020/02/03 Python
Jones New York官网:美国女装品牌,受白领女性欢迎
2019/11/26 全球购物
Michael Kors澳大利亚官网:世界知名的奢侈饰品和成衣设计师
2020/02/13 全球购物
电大毕业生自我鉴定
2013/11/10 职场文书
电子银行营销方案
2014/02/22 职场文书
八一建军节感言
2014/02/28 职场文书
车辆工程专业求职信
2014/04/28 职场文书
信息员培训方案
2014/06/12 职场文书
党员教师批评与自我批评发言稿
2014/10/15 职场文书
2014年大学教师工作总结
2014/12/02 职场文书
个人委托书范文
2015/01/28 职场文书
如何用python清洗文件中的数据
2021/06/18 Python