面向对象=====>工程模式/构造函数/原型模式

什么是面向对象?面向对象是一种思想!(废话)。

  面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法。这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作。接下来将为大家讲解在JS中面向对象的实现。

   工厂模式

  工厂模式是软件工程领域一种广为人知的设计模式,而由于在ECMAScript中无法创建类,因此用函数封装以特定接口创建对象。其实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性及方法再将对象返回即可。

function createBlog(name, url) {
  var o = new Object();
  o.name = name;
  o.url = url;
  o.sayUrl= function() {
    alert(this.url);
  }
  return o;
}

var blog1 = createBlog(‘wuyuchang‘, ‘http://www.jb51.net/‘);

可以看到工厂模式的实现方法非常简单,解决了创建多个相似对象的问题,但是工厂模式却无从识别对象的类型,因为全部都是Object,不像Date、Array等,因此出现了构造函数模式。

  构造函数模式

  ECMAScript中构造函数可以创建特定类型的对象,类似于Array、Date等原生JS的对象。其实现方法如下:

function Blog(name, url) {
  this.name = name;
  this.url = url;
  this.alertUrl = function() {
    alert(this.url);
  }
}

var blog = new Blog(‘wuyuchang‘, ‘http://www.jb51.net/‘);
console.log(blog instanceof Blog);  // true, 判断blog是否是Blog的实例,即解决了工厂模式中不能

这个例子与工厂模式中除了函数名不同以外,细心的童鞋应该发现许多不同之处:

函数名首写字母为大写  (虽然标准没有严格规定首写字母为大写,但按照惯例,构造函数的首写字母用大写
没有显示的创建对象
直接将属性和方法赋值给了this对象
没有return语句
使用new创建对象
能够识别对象(这正是构造函数模式胜于工厂模式的地方)

  构造函数虽然好用,但也并非没有缺点,使用构造函数的最大的问题在于每次创建实例的时候都要重新创建一次方法(理论上每次创建对象的时候对象的属性均不同,而对象的方法是相同的),然而创建两次完全相同的方法是没有必要的,因此,我们可以将函数移到对象外面(也许有些童鞋已经看出缺点,嘘!)。

function Blog(name, url) {
  this.name = name;
  this.url = url;
  this.alertUrl = alertUrl;
}

function alertUrl() {
  alert(this.url);
}

var blog = new Blog(‘scjb51‘, ‘http://sc.jb51.net/‘),
  blog2 = new Blog(‘jb51‘, ‘http://www.jb51.net/‘);
blog.alertUrl();  // http://sc.jb51.net/
blog2.alertUrl();  // http://www.jb51.net/

我们将alertUrl设置成全局函数,这样一来blog与blog2访问的都是同一个函数,可是问题又来了,在全局作用域中定义了一个实际只想让Blog使用的函数,显示让全局作用域有些名副其实,更让人无法接受的是在全局作用域中定义了许多仅供特定对象使用的方法,浪费空间不说,显然失去了面向对象封装性了,因此可以通过原型来解决此问题。

  原型模式

  我们创建的每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处就是可以让所有对象实例共享它所包含的属性及方法。

function Blog() {
}

Blog.prototype.name = ‘wuyuchang‘;
Blog.prototype.url = ‘http://tools.jb51.net/‘;
Blog.prototype.friend = [‘fr1‘, ‘fr2‘, ‘fr3‘, ‘fr4‘];
Blog.prototype.alertInfo = function() {
  alert(this.name + this.url + this.friend );
}

// 以下为测试代码
var blog = new Blog(),
  blog2 = new Blog();
blog.alertInfo();  // wuyuchanghttp://tools.jb51.net/fr1,fr2,fr3,fr4
blog2.alertInfo();  // wuyuchanghttp://tools.jb51.net/fr1,fr2,fr3,fr4

blog.name = ‘wyc1‘;
blog.url = ‘http://***.com‘;
blog.friend.pop();
blog2.name = ‘wyc2‘;
blog2.url = ‘http://+++.com‘;
blog.alertInfo();  // wyc1http://***.comfr1,fr2,fr3
blog2.alertInfo();  // wyc2http://+++.comfr1,fr2,fr3

原型模式也不是没有缺点,首先,它省略了构造函数传递初始化参数这一环节,结果所有实例在默认情况下都取得了相同的属性值,这样非常不方便,但这还是不是原型的最大问题,原型模式的最大问题在于共享的本性所导致的,由于共享,因此因此一个实例修改了引用,另一个也随之更改了引用。因此我们通常不单独使用原型,而是结合原型模式与构造函数模式。

  混合模式(原型模式 + 构造函数模式)

function Blog(name, url, friend) {
  this.name = name;
  this.url = url;
  this.friend = friend;
}

Blog.prototype.alertInfo = function() { //这段会代码执行多次 alert(‘exe time‘)
  alert(this.name + this.url + this.friend);
}

var blog = new Blog(‘wuyuchang‘, ‘http://tools.jb51.net/‘, [‘fr1‘, ‘fr2‘, ‘fr3‘]),
  blog2 = new Blog(‘wyc‘, ‘http://**.com‘, [‘a‘, ‘b‘]);

blog.friend.pop();
blog.alertInfo();  // wuyuchanghttp://tools.jb51.net/fr1,fr2
blog2.alertInfo();  // wychttp://**.coma,b

混合模式中构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。每个实例都会有自己的一份实例属性,但同时又共享着方法,最大限度的节省了内存。另外这种模式还支持传递初始参数。优点甚多。这种模式在ECMAScript中是使用最广泛、认同度最高的一种创建自定义对象的方法。

  动态原型模式

  动态原型模式将所有信息封装在了构造函数中,而通过构造函数中初始化原型(仅第一个对象实例化时初始化原型),这个可以通过判断该方法是否有效而选择是否需要初始化原型。

function Blog(name, url) {
  this.name = name;
  this.url = url;

  if (typeof this.alertInfo != ‘function‘) {
    // 这段代码只执行了一次
    alert(‘exe time‘);
    Blog.prototype.alertInfo = function() {
      alert(thia.name + this.url);
    }
  }
}

var blog = new Blog(‘wuyuchang‘, ‘http://tools.jb51.net‘),
  blog2 = new Blog(‘wyc‘, ‘http:***.com‘);

可以看到上面的例子中只弹出一次窗,‘exe time‘,即当blog初始化时,这样做blog2就不在需要初始化原型,对于使用这种模式创建对象,可以算是perfect了。

时间: 2024-10-10 02:30:06

面向对象=====>工程模式/构造函数/原型模式的相关文章

面向对象JS基础讲解,工厂模式、构造函数模式、原型模式、混合模式、动态原型模式

什么是面向对象?面向对象是一种思想!(废话). 面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下来将为大家讲解在JS中面向对象的实现. 工厂模式 工厂模式是软件工程领域一种广为人知的设计模式,而由于在ECMAScript中无法创建类,因此用函数封装以特定接口创建对象.其实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性及方法再将对象返回即可. function createBlog(

JS面向对象(1)——构造函数模式和原型模式

1.构造函数模式 构造函数用来创建特定的类型的对象.如下所示: function Person(name,age,job){ this.name=name; this.job=job; this.age=age; this.sayName=function(){ alert(this.name); }; } var person1=new Person('nick',20,'student');var person2=new Person('nick',20,'student');alert(p

JavaScript之面向对象学习七(动态原型模式和寄生构造函数模式创建自定义类型)

一.动态原型模式 在面向对象学习六中的随笔中,了解到组合构造函数模式和原型模式创建的自定义类型可能最完善的!但是人无完人,代码亦是如此! 有其他oo语言经验的开发人员在看到独立的构造函数和原型时,很可能会感到非常困惑.因为对象在其他oo语言中往往是封装在一块的,而构造函数确是和原型分开的,所以并没有真正意义上的封装,所以动态原型模式正是致力与解决这一问题的一个方案! 动态原型模式将所有的信息都封装在构造函数中(包括原型和实例属性),通过在构造函数中实例化原型(仅在必要的情况下)实现封装,又保持了

Javascript 构造函数模式、原型模式

前两天写完组合继承,打算总结一下原型继承的,不过今天看了一下工厂模式.构造函数模式和原型模式,觉得有必要总结一下以加深印象. ——————————————————————————————————————————————————————————————————————————————————碎碎念. 1.工厂模式 <Javascript 高级程序设计(第3版)> 用了寥寥十多行介绍了工厂模式.我找了一些相关资料,想确定一下这种模式的具体适用场景和优势.按照资料中的说法,是考虑到 ECMAScri

js设计模式:工厂模式、构造函数模式、原型模式、混合模式

一.js面向对象程序 var o1 = new Object(); o1.name = "宾宾"; o1.sex = "男"; o1.age = "27"; o1.msg = function(){ console.log("姓名:"+this.name+"  性别:"+this.sex+"  年龄:"+this.age); } var o2 = new Object(); o2.nam

js - 创建对象的几种方式(工厂模式、构造函数模式、原型模式)

原文引用https://www.dazhuanlan.com/2019/08/26/5d62f8b594f10/ 工厂模式 做法:内部创建一个对象,并未对象属性赋值并且返回 缺点:解决创建多个相识对象的问题,但不能识别创建的对象的类型 构造函数模式 做法:直接将属性和方法赋值给 this 对象,没有 return 语句 缺点:对象不是共用方法和属性,每 new 一次对象就要创建一个内存,超出性能消耗 原型模式 做法:通过 prototype 为对象添加属性 缺点:每个实例都共享属性方法,实例中修

组合使用构造函数模式和原型模式和寄生构造函数

chuangjian自定义类型的最常见方式就是组合使用构造函数模式与原型模式,构造函数模式用于定义实力属性,原型模式定义方法和共享的属性. 寄生构造函数: 原来的写法 var array1 = ['1','2'];var array2 = ['1','2','3'];array1.a = function () { alert(this.length);};array1.a();array2.a = function () { alert(this.length);};array2.a(); 与

JS创建对象模式及其对象原型链探究(五):组合使用构造函数模式和原型模式

组合使用构造函数模式和原型模式 构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性. 创建自定义类型的最常见方式,就是组合使用构造函数模式和原型模式. 1.创建对象 // 组合使用构造函数模式和原型模式 function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.friend = ["Jenny", "Court"]; } Person.p

浅议javascript的工厂模式,构造函数模式及原型模式

通常来讲我们一般这样创建对象: (1)  var jxj=new Object(); jxj.name="jxj"; jxj.sayHi=function(){console.log("O(∩_∩)O哈哈哈~")}: (2)  var   jxj={name:"jxj",age:"24",.....} 这两种方式在一些场景简单,规模小的项目中使用,我们还可以忍受:但这种方式在可拓展性,可维护性等等方面有很多的问题,于是,就出现