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 相关文章推荐
点击文章内容处弹出页面代码
Oct 01 Javascript
IE 上下滚动展示模仿Marquee机制
Dec 20 Javascript
javascript针对DOM的应用分析(四)
Apr 15 Javascript
JavaScript 开发工具webstrom使用指南
Dec 09 Javascript
JS使用正则表达式实现关键字替换加粗功能示例
Aug 03 Javascript
jQuery时间日期三级联动(推荐)
Nov 27 Javascript
全面总结Javascript对数组对象的各种操作
Jan 22 Javascript
js实现添加删除表格(两种方法)
Apr 27 Javascript
Three.js加载外部模型的教程详解
Nov 10 Javascript
jQuery实现的中英文切换功能示例
Jan 11 jQuery
Vue3 中的数据侦测的实现
Oct 09 Javascript
Node.js操作MongoDB数据库实例分析
Jan 19 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
历史证明,懒惰才是推动科学发展技术进步的动力
2021/03/02 无线电
我的论坛源代码(一)
2006/10/09 PHP
?繁体转换的class
2006/10/09 PHP
php笔记之:有规律大文件的读取与写入的分析
2013/04/26 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
PHP 记录访客的浏览信息方法
2018/01/29 PHP
Js制作点击输入框时默认文字消失的效果
2015/09/05 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
2016/04/26 Javascript
Vue.js学习示例分享
2017/02/05 Javascript
Bootstrap的Carousel配合dropload.js实现移动端滑动切换图片
2017/03/10 Javascript
微信小程序 监听手势滑动切换页面实例详解
2017/06/15 Javascript
10个最优秀的Node.js MVC框架
2017/08/24 Javascript
微信小程序-getUserInfo回调的实例详解
2017/10/27 Javascript
React Native基础入门之调试React Native应用的一小步
2018/07/02 Javascript
微信小程序使用template标签实现五星评分功能
2018/11/03 Javascript
Cookbook组件形式:优化 Vue 组件的运行时性能
2018/11/25 Javascript
零基础写python爬虫之爬虫框架Scrapy安装配置
2014/11/06 Python
python实现JAVA源代码从ANSI到UTF-8的批量转换方法
2015/08/10 Python
python+selenium+autoit实现文件上传功能
2017/08/23 Python
python编写弹球游戏的实现代码
2018/03/12 Python
python实现文件助手中查看微信撤回消息
2019/04/29 Python
Python read函数按字节(字符)读取文件的实现
2019/07/03 Python
详解python 利用echarts画地图(热力图)(世界地图,省市地图,区县地图)
2019/08/06 Python
python 微信好友特征数据分析及可视化
2020/01/07 Python
Python with标签使用方法解析
2020/01/17 Python
Python *args和**kwargs用法实例解析
2020/03/02 Python
Ubuntu20.04环境安装tensorflow2的方法步骤
2021/01/29 Python
浅谈cookie和localStorage那些事
2019/08/27 HTML / CSS
在线服装零售商:SheIn
2016/07/22 全球购物
Godiva巧克力英国官网:比利时歌帝梵巧克力
2018/08/28 全球购物
英国领先的露营和露营车品牌之一:OLPRO
2019/08/06 全球购物
Linux Interview Questions For software testers
2012/06/02 面试题
失业者真诚求职信范文
2013/12/25 职场文书
上诉状格式
2015/05/23 职场文书
教你怎么用Python处理excel实现自动化办公
2021/04/30 Python
Window server中安装Redis的超详细教程
2021/11/17 Redis