学习js面向对象编程设计模式

news/2024/7/19 15:50:20 标签: js, 设计模式

目录

 

描述

创建对象

工厂模式

构造函数模式

原型模式

构造函数模式+原型模式

寄生构造模式

稳妥构造函数模式


描述

面向对象的语言有一个标志,就是都有类的概念,而通过类可以创建很多具有相同属性和方法的对象。

对象可以定义为无序属性的集合,其属性可以包含基本值,对象或者函数

创建对象

创建自定义对象的最简单的方式就是创建一个Object的实例。

let cat = new Object()
cat.name = 'Tom'
cat.age = 2
cat.eat = function(){
  alert('吃鱼')
}

//当然用对象字面量表示法更方便
let cat = {
  name: 'Tom',
  age: 2,
  eat: function() {
    alert('吃鱼')
  }
}

但是这样会产生大量重复的代码

工厂模式

在es5中,没有类的概念,于是提出了用函数来封装以特定接口创建对象的细节:

function cat(name, age, color){
   let cat = new Object()
   cat.name = name;
   cat.age = age;
   cat.color = '黄色'
   cat.eat = function() {
     alert('吃肉')
   }
   return cat
}
let cat1 = new Cat('Tom', 2, '黄色')
let cat2 = new Cat('jack', 1, '棕色')

这样就能够一个函数创建多个实例了,就相当于Cat这个工厂,专门用来生产cat实例,只需要给工厂传递想要的参数即可。

在es6中 提出了class的概念 ,class可以看做是一个语法糖,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已

class Cat {
  constructor(age, name, color='白色') {   //默认白色
    this.age = age;
    this.name = name;
    this.color = color;
  }
  eat() {
    alert(`${this.name}爱吃鱼`)
  }
}
let cat1 = new Cat(12, 'tom', 'yellow')
let cat2 = new Cat(12,, 'jack')

简单工厂模式的缺点也很突出:没有解决对象识别的问题(即怎样知道一个对象的类型)

构造函数模式

构造函数与工厂模式主要有几个不同:

1.没有显示的创建对象

2.直接将属性和方法赋值给this对象

3.没有return语句

4.函数大写开头,主要是为了区别其他函数,构造函数也是函数,只不过能用来创建对象罢了。

function Cat(name, age, color){
   this.name = name;
   this.age = age;
   this.color = '黄色'
   this.eat = function() {
     alert(`${this.name}爱吃鱼`)
   }
}
let cat1 = new Cat('Tom', 2, '黄色')
let cat2 = new Cat('jack', 1, '棕色')

缺点:构造函数中每个方法都要在实例上重新创建一遍,在上面例子中,虽然eat方法都可以弹出信息,但是其实cat1.eat和cat2.eat这两个方法指向地址是不同的

console.log(cat1.eat === cat2.eat)   //false

我们可以在外部创建一个函数来解决共享问题

function Cat(name, age, color){
   this.name = name;
   this.age = age;
   this.color = '黄色'
   this.eat = eat
}
function eat() {
  alert(`${this.name}爱吃鱼`)
}
let cat1 = new Cat('Tom', 2, '黄色')
let cat2 = new Cat('jack', 1, '棕色')

这样一来eat就是指向eat函数地址的一个指针,就可以共享eat方法了。

可是新问题又来了,这样eat方法只能被某个对象调用,让全局作用域名不副实啊,关键是,如果对象需要很多方法,那再全局作用域中岂不全是全局函数?这样我们自定义的引用类型就完全没有封装性可言了,好在可以用原型模式来解决

原型模式

我们创建的每一个函数都有一个prototyp属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法

function Cat(){

}
Cat.prototype.name = 'tom'
Cat.prototype.age = 12
Cat.prototype.eat = function() {
  alert(`${this.name}爱吃鱼`)
}
let cat1 = new Cat('Tom', 2, '黄色')
let cat2 = new Cat('jack', 1, '棕色')

//或者,注意这样其实是重写整个原型对象,也就是将prototype指向一个新对象
,如果是在重写原型对象之前创建实例,那么原来的实例指向的还是未重写之前的原型对象。
Cat.prototype = {
   name: 'tom',
   age: 12,
   eat: fuction() {
     alert(`${this.name}爱吃鱼`)
   }
}

缺点:首先是忽略了为构造函数传递参数,其次在原型中所有属性和方法都是共享的,但是每个实例都应该有各自的属性,比如cat1名字为tom,cat2名字为jack,而不是每个实例都是tom.

构造函数模式+原型模式

function Cat(name, age){
  this.name = name;
  this.age = age;
}
Cat.prototype.eat = function() {
  alert(`${this.name}爱吃鱼`)
}
let cat1 = new Cat('Tom', 2, '黄色')
let cat2 = new Cat('jack', 1, '棕色')

//或者,注意这样其实是重写整个原型对象,也就是将prototype指向一个新对象
,如果是在重写原型对象之前创建实例,那么原来的实例指向的还是未重写之前的原型对象。
Cat.prototype = {
   name: 'tom',
   age: 12,
   eat: fuction() {
     alert(`${this.name}爱吃鱼`)
   }
}

寄生构造模式

可以为对象创建构造函数,例:用来创建一个具有额外方法的数组。由于不能直接修改Array构造函数,可以用该模式

function SpecialArray() {
  let arr = new Array()
  arr.push.apply(arr,arguments)
  arr.toSpecialString = function() {
    return this.join('|')
  }
  return arr
}
let special = new SpecialArray(1,2,3,4)
special.toSpecialString() //1|2|3|4

稳妥构造函数模式

稳妥构造函数模式使用稳妥对象,稳妥对象指没有公共属性,而且其方法不引用this的对象,适合用在安全的环境中(这些环境禁止使用this和new)。

稳妥构造函数模式和寄生构造函数模式有两点不同:1.新创建的实例方法不引用this;2.不使用new操作符调用构造函数。

function Cat(name, age) {
  let cat = new Cart()
  cat.name = name;
  cat.age = age
  cat.eat = function() {
    alert(`${name}爱吃鱼`)
  }
  return cat
}
let cat = Cat('tom', 12)
cat.eat()    //tom爱吃鱼

参考文章:《javascript高级程序设计》


http://www.niftyadmin.cn/n/1869601.html

相关文章

python3函数语法_Python3基础语法12--函数

1.定义 将具有独立功能的代码块组成一个整体,使其具有特殊功能的代码集 创建函数叫做函数定义,创建后使用函数叫做函数的调用 2.作用 加强代码复用性,提高写代码的效率 3.格式一(无参数无返回值) 定义格式一: def 函数名(): 函数体 调用格式一: 函数名() 注意:调用时函数必须先…

js中实例方法、静态方法和原型方法详解

背景 之前一直以为构造函数可以直接访问原型方法,是错的,现在说一下 实例方法 构造函数中this上添加的成员 ,在Cat构造方法里面,定义在this中的变量和方法,只有实例才能访问到:如this.name,this.move,this.eat这些都…

python requests get请求_python+requests进行get、post方法接口测试

简介:Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的&…

react-动态声明类名和动态设置内联样式

需求 1.有一列导航条,我们需要根据当前点击的导航来设置样式。 2。表格中有价格一列,价格为空时显示为-,不为空时显示价格, 但是价格是红色,如下 当金额小记为空时,显示的时黑色的-,有价格时应…

设置Tomcat默认访问路径

步骤&#xff1a; 1、打开server.xml,在</Host>的上一行添加内容格式如下 <Context path"" reloadable"true" docBase"<项目名>"/> 如: <Context path"" docBase"gps" debug"0" reloada…

java cxf 第一次特别慢_Java程序员,按照这份模板“优化”简历,至少让你涨薪50%!...

​什么是好的技术简历&#xff1f;首先&#xff0c;一份好的简历不光说明事实&#xff0c;更通过FAB模式来增强其说服力。Feature&#xff1a;是什么Advantage&#xff1a;比别人好在哪些地方Benefit&#xff1a;如果雇佣你&#xff0c;招聘方会得到什么好处其次&#xff0c;写…

ant-degisn的数字输入框的使用和表格的价格计算

需求 1.最近在项目中需要用表格计算价格&#xff0c;所以需要用到ant-design中的数字输入框。如下图 这里有两个表格&#xff0c;我需要实现的是 1.表格内价格的计算和总价格的计算 2.数字输入框只能输入1-99的数字&#xff0c;不能输入中文。 实现 1.数据格式。 这里从…

Vue脚手架(vue-cli)搭建和目录结构详解

一、环境搭建 1、安装node、npm、webpack&#xff0c;不多说 2、安装vue-cli脚手架构建工具&#xff0c;打开命令行工具输入&#xff1a;npm install vue-cli -g&#xff0c;安装完成之后输入 vue -V&#xff08;注意这里是大写的“V”&#xff09;&#xff0c;如果出现相应的版…