Javaspript封装
1、面向对象语言的要求
(1)封装—把相关的信息(无论数据或方法)存储在对象中的能力
(2)聚集—把一个对象存储在另一个对象内的能力
(3) 继承—由另一个类(或多个类)得来类的属性和方法的能力
(4)多态—编写能以多种方法运行的函数或方法的能力
ECMAScript支持这些要求,因此可被看作面向对象的.
2、对象的实例化
var obj = new Object()
var ostringobj = new String()
ECMAScript中也可以把()去掉
var obj = new object;
var ostringobj = new String;
3、对象废除
ECMAScript中有无用存储单元收集程序,意味着不必专门销毁对象来释放内存.
也可强制废除对象:eg:
var obj = new Object();
obj = null
5、对象类型
5.1 本地对象
Object Array Function String Boolean Number Date RegExp Error EvalError RangeError ReferenceError SyntaxError TypeError URIError
5.2 自定义对象
6、作用域,全部都是公共的
对ECMAScript来说,讨论作用域几乎毫无意义。ECMAScript只存在一种作用域(公有作用域)
许多开发都制定了一个规约:私有的属性建议前后加下划线,如:obj._color_ = “red”;
7、静态作用域并非静态的
严格来说,ECMAScript并没有静态作用域,不过,它可以给构造函数提供属性和方法. 构造函数是函数,函数是对象,对象可以有属性和方法。
如:function sayHi(){
alert(“hi”); };
sayHi.alternate = function(){ alert(“hellow”);}
调用:
sayHi(); sayHi.alternate();
8、关键字this
在ECMAScript中,要掌握的最重要的概念之一是关键字this的用法.
它用在对象的方法中,关键字this总是指向调用该方法的对象:
eg:
var oCar = new Object();
oCar.color=“red”;
oCar.showColor=function(){
alert(this.color); //等价于 oCar.color
}
说明:利有this,可在任意多个地方重用同一个函数.
谁调用它这个this就指向谁
如:function ShowColor()
{
alert(this.Color);
}
var oCar1 = new Object();
oCar1.Color = “red”;
oCar1.ShowColor = ShowColor; //这时this是ocar1
var oCar2 = new Object();
oCar2.Color = “blue”;
oCar2.ShowColor=ShowColor; //这时this是ocar2
oCar1.ShowColor(); // output “red”
oCar2.ShowColor(); //outpub “blue”
注意:引用对象的属性时必须使用this.
eg: function ShowColor()
{
alert(Color); //error
}
自定义类和对象
1、工厂模式
ECMAScript中对象的属性可在对象创建后动态定义.
如:
var oCar = new Object();
oCar.Color = "red";
oCar.doors = 4;
oCar.mpg = 23;
oCar.ShowColor = function(){
alert(this.Color);
}
调用时 oCar.ShowColor(); //output “red”
问题:需要创建多个Car实例怎么办?
工厂模式:
function CreateCar(){ //每次调用都创建新的实例
var oCar = new Object();
oCar.Color = "red";
oCar.doors = 4;
oCar.ShowColor = function(){
alert(this.Color);
}
return oCar;
}
调用:
var car1 = CreateCar();
var car2 = CreateCar();
car2.color=’blue’;
alert(car1.Color); //output “red”
car2.ShowColor(); //output “blue”
改造并加入参数:
function CreateCar(color,doors,mpg){
var oCar = new Object();
oCar.Color = color;
oCar.doors = doors;
oCar.mpg = mpg;
oCar.ShowColor = function(){
alert(this.Color); }
return oCar; }
var car1 = CreateCar("red",4,23);
var car2 = CreateCar("blue",4,20);
alert(car1.Color); //output “red”
car2.ShowColor(); //output “blue”
JavaScript中的封装
问题:上面的例子中,每次调用函数createCar(),都要创建新函数showColor(),意味着每个对象都有自己的showColor()版本,事实上,每个对象都共享了同一个函数 ,showColor每次创建都要分配内存空间
解决方法:
function showColor()
{
alert(this.color);
}
function createCar(sColor,iDoors,iMpg)
{
var oTempCar = new Object();
oTempCar.color = sColor;
oTempCar.doors = iDoors;
oTempCar.mpg= iMpg;
oTempCar.showColor = showColor;
return oTempCar;
}
var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);
oCar1.showColor(); //output “red”
oCar2.showColor(); //output “blue”
问题2
问题:从功能上讲,这样解决了重复创建函数对象的问题,但该函数看起来不像对象的方法.
解决办法:
所有这些问题引发了开发者定义的构造函数的出现
构造函数方式
形式如下:
function Car(sColor,iDoors) {
this.color = sColor;
this.doors = iDoors;
this.showColor=function(){
alert(this.color); } }
// oCar.ShowColor = function(){
// alert(this.Color); }
//调用
var oCar1 = new Car(“red”,4);
var oCar2 = new Car(“blue”,4);
oCar1.showColor();
oCar2.showColor();
问题:存在着和工厂模式相同的问题,创建对象的方法,都分配内存空间
解决方法:也可以用外部函数重写构造函数,同样的,语义上无任何意义.这就是原型方式的优势所在.
function Car(){};//相当于定义了一个空的类
Car.prototype.color = “red”;//object的一个属性prototype
Car.prototype.doors = 4;
Car.prototype.showColor = function(){
alert(this.color);
}
//调用
var oCar1= new Car();
var oCar2 = new Car();
oCar1.showColor(); //output “red”
oCar2.color=“blue”;
oCar2.showColor(); //output “blue”,需要实例化的时候才分配内存空间
此种方式,调用new Car()时,原型的所有属性都被立即赋予要创建的对象,意味着所有Car实例存放的都是指向showColor()函数的指针.所有属性看起来都属于同一个对象,因此解决了前面两种方式的两个问题
可以用instanceof运算符测试对象的类型
eg: alert(oCar1 instanceof Car) //output “true”;
问题:
1、 构造函数没有参数.必须创建后才能改变属性的默认值,有些讨厌
2、真正的问题在于,当属性指向对象时,对象会被多个实例共享。不灵活
如:
function Car(){};
Car.prototype.color = “red”;
Car.prototype.doors = 4;
Car.prototype.showColor = function(){
alert(this.color);
}
Car.prototype.drivers = new Array(“a”,”b”);
//call
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.drivers.push(“c”);
alert(oCar1.drivers); //output “a”,”b”,”c”;
alert(oCar2.drivers); //outpub “a”,”b”,”c”;
解决方法: 联合使用构造函数和原型方式
联合使用构造函数和原型方式,就可像用其他程序设计语言一样创建对象.这种概念非常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法).结果所有函数都只创建一次,而每个对象都具有自己的对象属性实例.
eg:
function Car(sColor,iDoors){//实例化的时候不实例化ShowColor这个函数
this.color = sColor;
this.doors = iDoors;
this.drivers = new Array();
}
Car.prototype.ShowColor = function(){
alert(this.color);
}
//Call
var oCar1 = new Car(“red”,4,23);
var oCar2 = new Car(“blue”,3,25);
oCar1.drivers.push(“a”);
oCar2.drivers.push(“b”);
alert(oCar1.drivers); //output “a”;
alert(oCar2.drivers); //output “b”;
} 问题:此种方式已接近完善
但类的定义分散在两部分,感觉还不是很完美
解决办法:
动态原型方法
Function Car(sColor,iDoors,iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers=new Array();
if (typeof Car._initialized==“undefined”){//initialized随便起的,刚创建的时候肯定不存在
Car.prototype.showColor = function(){
alert(this.color);
};
Car._initialized = true;
//下次再定义这个类的实例,initalized就有值了,就不会重新定义这个方法了
}
}
//call
} var oCar = new Car("yellow",10,20);
} oCar.showColor(); //output “yellow”
采用哪种方式?
如前所述,目前使用最广泛的是混合的构造函数/原型方法.此外,动态原型方法也很流行,功能上和前者等价.可以采用上述方法中的一种.
实例:
1、利用javaScript的面向对象技术封装一个字符串连结的类.
传统的方式:
var str=“hellow”
str +=“world”
缺点:字符串的不变性,导致这种做法很没有效率
} 改进一
var Arr = new Array();
Arr[0]=“hellow”;
Arr[1]=“world”;
var str = Arr.join(““);
虽然解决了效率问题,但不太优雅.
} 改进二
function StringBuffer()
{
this._strings_=new Array(); //私用属性
}
StringBuffer.prototype.append = function(str)
{
this._strings_.push(str);
}
StringBuffer.prototype.toString=function(){
return this._strings_.join(“”);
// join() 方法用于把数组中的所有元素放入一个字符串。
}
} //call 使用
} var strobj = new StringBuffer();
} strobj.append("hellow");
} strobj.append("world");
} alert(strobj.toString());
修改对象已有的属性,创建新方法
Eg1:
Number.prototype.toHexString=function()
{
return this.toString(16);
}
//call
var iNum=15;
alert(iNum.toHexString()); //output “f”
} Eg2 给array扩展3个方法
Array.prototype.enqueue=function(vItem)
{
this.push(vItem);//想对象添加值
}
Array.prototype.dequeue = function()
{
return this.shift();
shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
}
Array.prototype.indexOf=function(vItem){
for(var i=0;i<this.length;i++)
{
if (vItem == this[i])
return i;
}
return -1;
}
} //call
} var arr = new Array();
} arr.enqueue("aaa");
} arr.enqueue("bbb");
} arr.enqueue("ccc");
} arr.dequeue();
} alert(arr.indexOf("aaa"));
Eg3.扩展Object
Object.prototype.alert = function()
{
alert(this.valueOf());
}
//call
var str=“hellow”;
var iNum = 25;
str.alert();
iNum.alert();
重定义已有方法
Function.prototype.toString = function(){
return “”; }
function sayHi(){
alert(“hi”); }
//call
alert(sayHi.toString()); //output “”
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述