轻松学习JavaScript十二:JavaScript基于面向对象之创建对象(二)

 四原型方式

       我们创建的每个函数都有一个通过prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型

的所有实例共享的属性和方法。逻辑上可以这么理解:prototypt通过条用构造函数而创建的那个对象的原型对象。使

用原型的好处就是可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而

是直接将这些信息添加到原型中。

       原型方式利用了对象的prototype 属性,可以把它看成创建新对象所依赖的原型。这里,首先用空构造函数来设置

函数名。然后所有的属性和方法都被直接赋予prototype属性。我重写了前面的例子,代码如下:

[javascript]  view plain copy print ?
  1. function Car() { };  
  2. //将所有的属性的方法都赋予prototype属性  
  3. Car.prototype.color = "blue";  
  4. Car.prototype.doors = 4;  
  5. Car.prototype.mpg = 25;  
  6. Car.prototype.showColor = function() {  
  7.      return this.color;  
  8. };  
  9. var Car1 = new Car();  
  10. var Car2 = new Car();  
  11. document.write(Car1.showColor()+"<br/>");//输出:blue  
  12. document.write(Car2.showColor());//输出:blue  

      在这段代码中,首先定义构造函数Car(),其中无任何代码。接下来的几行代码,通过给Car的 prototype 属性添加

属性去定义Car对象的属性。调用new Car()时,原型的所有属性都被立即赋予要创建的对象,意味着所有Car实例存

放的都是指向 showColor() 函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面的工厂方式

和构造函数方式存在的问题。

       此外,使用这种方式,还能用 instanceof 运算符检查给定变量指向的对象的类型:

[javascript]  view plain copy print ?
  1. <span style="font-size:18px;">document.write(Car1 instanceof Car);    //输出:true</span>  

      原型方式看起来是个不错的解决方案。遗憾的是,它并不尽如人意。首先,这个构造函数没有参数。使用原型方

式,不能通过给构造函数传递参数来初始化属性的值,因为Car1和Car2的color属性都等于 "blue",doors属性都等于

4,mpg属性都等于25。这意味着必须在对象创建后才能改变属性的默认值,这点很令人讨厌,但还没完。真正的问

题出现在属性指向的是对象,而不是函数时。函数共享不会造成问题,但对象却很少被多个实例共享。请思考下面的

例子:

[javascript]  view plain copy print ?
  1. function Car() { };//定义一个空构造函数,且不能传递参数   
  2. Car.prototype.color = "blue";  
  3. Car.prototype.doors = 4;  
  4. Car.prototype.mpg = 25;  
  5. Car.prototype.drivers = new Array("Mike","John");  
  6. Car.prototype.showColor = function() {  
  7.       return this.color;  
  8. };  
  9. var Car1 = new Car();  
  10. var Car2 = new Car();  
  11. Car1.drivers.push("Bill");  
  12. document.write(Car1.drivers+"<br/>");//输出:Mike,John,Bill  
  13. document.write(Car2.drivers);//输出 :Mike,John,Bill  

       上面的代码中,属性drivers是指向Array对象的指针,该数组中包含两个名"Mike"和 "John"。由于 drivers是引用

值,Car的两个实例都指向同一个数组。这意味着给Car1.drivers添加值 "Bill",在 Car2.drivers 中也能看到。输出这两

个指针中的任何一个,结果都是显示字符串 "Mike,John,Bill"。由于创建对象时有这么多问题,你一定会想,是否有种

合理的创建对象的方法呢?答案是有,需要联合使用构造函数和原型方式。

       五混合的构造函数/原型方式(推荐使用)

       混合使用构造函数方式和原型方式,就可像用其他程序设计语言一样创建对象。这种概念非常简单,即用构造函

数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。结果是,所有函数都只创建一次,而每个

对象都具有自己的对象属性实例。我们重写了前面的例子,代码如下:

[html]  view plain copy print ?
  1. function Car(Color,Doors,Mpg) {  
  2.   this.color = Color;  
  3.   this.doors = Doors;  
  4.   this.mpg = Mpg;  
  5.   this.drivers = new Array("Mike","John");  
  6. };  
  7. Car.prototype.showColor = function() {  
  8.          return this.color;  
  9. };  
  10. var Car1 = new Car("red",4,23);  
  11. var Car2 = new Car("blue",3,25);  
  12. Car1.drivers.push("Bill");  
  13. document.write(Car1.drivers+"<br/>");//输出:Mike,John,Bill  
  14. documnet.write(Car2.drivers);//输出:Mike,John  

       现在就更像创建一般对象了。所有的非函数属性都在构造函数中创建,意味着又能够用构造函数的参数赋予属性

默认值了。因为只创建showColor()函数的一个实例,所以没有内存浪费。此外,给Car1的drivers数组添加 "Bill" 值,

不会影响到Car2的数组,所以输出这些数组的值时,Car1.drivers 显示的是 "Mike,John,Bill",而 Car2.drivers 显示的

是 "Mike,John"。因为使用了原型方式,所以仍然能利用 instanceof运算符来判断对象的类型。

       这种方式是ECMAScript采用的主要方式,它具有其他方式的特性,却没有他们的副作用。不过,有些开发者仍觉

得这种方法不够完美。

      六动态原型方式

      对于习惯使用其他语言的开发者来说,使用混合的构造函数/原型方式感觉不那么和谐。毕竟,定义类时,大多数

面向对象语言都对属性和方法进行了视觉上的封装。请考虑下面的 Java 类:

[java]  view plain copy print ?
  1. class Car {  
  2.   public String color = "blue";  
  3.   public int doors = 4;  
  4.   public int mpg = 25;  
  5.   public Car(String color, int doors, int mpg) {  
  6.       this.color = color;  
  7.       this.doors = doors;  
  8.       this.mpg = mpg;  
  9.   }  
  10.   public void showColor() {  
  11.       System.out.println(color);  
  12.   }  
  13. }  

        Java很好地打包了Car类的所有属性和方法,因此看见这段代码就知道它要实现什么功能,它定义了一个对象的

信息。批评混合的构造函数/原型方式的人认为,在构造函数内部找属性,在其外部找方法的做法不合逻辑。因此,他

们设计了动态原型方法,以提供更友好的编码风格。

       动态原型方法的基本想法与混合的构造函数/原型方式相同,即在构造函数内定义非函数属性,而函数属性则利用

原型属性定义。唯一的区别是赋予对象方法的位置。下面是用动态原型方法重写的Car:

[javascript]  view plain copy print ?
  1. function Car(Color,Doors,Mpg) {  
  2.   this.color = Color;  
  3.   this.doors = Doors;  
  4.   this.mpg = Mpg;  
  5.   this.drivers = new Array("Mike","John");  
  6.   //如果Car对象中的_initialized为undefined,表明还没有为Car的原型添加方法  
  7.   if (typeof Car._initialized == "undefined") {  
  8.          Car.prototype.showColor = function() {  
  9.                 return this.color;  
  10.          };   
  11.          Car._initialized = true//设置为true,不必再为prototype添加方法  
  12.   }  
  13. }  
  14. var Car1 = new Car("red",4,23);//生成一个Car对象  
  15. var Car2 = new Car("blue",3,25);  
  16. Car1.drivers.push("Bill");//向Car1对象实例的drivers属性添加一个元素  
  17. document.write(Car1.drivers+"<br/>");//输出:Mike,John,Bill  
  18. document.write(Car2.drivers);//输出:Mike,John  

       直到检查typeof Car._initialize是否等于"undefined"之前,这个构造函数都未发生变化。这行代码是动态原型方法

中最重要的部分。如果这个值未定义,构造函数将用原型方式继续定义对象的方法,然后把 Car._initialized设置为

true。如果这个值定义了(它的值为 true时,typeof 的值为Boolean),那么就不再创建该方法。简而言之,该方法使用

标志(_initialized)来判断是否已给原型赋予了任何方法。该方法只创建并赋值一次,传统的 OOP开发者会高兴地发

现,这段代码看起来更像其他语言中的类定义了。

       我们应该采用哪种方式呢?

       如前所述,目前使用最广泛的是混合的构造函数/原型方式。此外,动态原型方式也很流行,在功能上与构造函

数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给

代码引入问题。总之JS是基于面向对象的一门客户端脚本语言,我们在学习它的面向对象技术的时候要的留意JS与

其他严谨性高的程序语言的不同。也要正确使用JS创建对象的合理的方式,推荐使用构造函数与原型方式的混合方式

创建对象实例。这样可以避免许多不必要的麻烦。


转载自:http://blog.youkuaiyun.com/erlian1992/article/details/50224073

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值