js面向对象编程OOP及函数式编程FP区别

目录
  • 写在前面
  • javscript 中函数和对象的关系
  • 面向对象编程(OOP)
    • 继承
    • 多态
    • 封装
  • 函数编程编程(FP)
    • 闭包和高阶函数
    • 柯里化
    • 偏函数
    • 组合和管道
    • 函子
  • 写在最后

写在前面

浏览下文我觉得还是要有些基础的!下文涉及的知识点太多,基本上每一个拿出来都能写几篇文章,我在写文章的过程中只是做了简单的实现,我只是提供了一个思路,更多的细节还是需要自己去钻研的,文章内容也不少,辛苦,如果有其他的看法或者意见,欢迎指点,最后纸上得来终觉浅,绝知此事要躬行

javscript 中函数和对象的关系

javscript 一切皆为对象,但基本类型之外,函数是对象,对象是由函数创建而来, 从而衍生出我对这两种编程方式的探讨。下面对类型判断和原型做了一个简单的表述,这里不是重点,不做具体的表述,感兴趣的可以自己百度/谷歌。

// 类型判断
// 基本类型
console.log(typeof 1)                               // | ==> number
console.log(typeof '2')                             // | ==> string
console.log(typeof undefined)                       // | ==> undfined
// null 类型判断【特殊】
console.log(typeof null)                            // | ==> object
console.log(Object.prototype.toString.call(null))   // | ==> [object Null]
// 报错【null 不是一个对象】TypeError: Right-hand side of 'instanceof' is not an object
console.log(null instanceof null)
console.log(typeof Symbol())                        // | ==> symbol 【ES6 新类型】
console.log(typeof false)                           // | ==> boolean
console.log(typeof BigInt(9007199254740991n))       // | ==> bigint 【新类型】
// 引用类型 - 对象
console.log(typeof (() => {}))                      // | ==> function
console.log((() => {}) instanceof Object)           // true
console.log(typeof [])                              // | ==> object
console.log(typeof {})                              // | ==> object
console.log(typeof (/\./))                          // | ==> object
console.log(typeof new Date())                      // | ==> object
console.log(typeof new String())                    // | ==> object
console.log(typeof new Number())                    // | ==> object
// 原型链
// fn ====> function fn () {}
// Object ====> function Object () {}
// Function ====> function Funtion()
    new fn() - __proto__ --|
      ↑                    ↓
---→ fn ----------- fn.prototype -------- __proto__ -----→ Object.prototype -- __proto__--→ null
      |                                                                  ↑
      |--------- __proto__ ------→ Function.prototype --- __proto__ -----|
                                        ↑
                  Function -------→ __proto__
                                        |
                                      Object

面向对象编程(OOP)

在面向对象编程中最常见的表现形式就是类,提供了面向对象的 大特点和 ️ 大原则,这东西网上特别多,我只做简单的罗列,下面我会对特点进行实现,我的理解: 原则是面向对象编程的规范,而特点是面向对象编程的实现,前提是你已经仔细理解过下面对核心概念。

三大特点

  • 继承
  • 多态
  • 封装

五大原则

  • 单一 【一个类应该有且只有一个去改变它的理由,这意味着一个类应该只有一项工作】
  • 开放封闭 【对象或实体应该对扩展开放,对修改封闭。】
  • 里氏替换 【即对父类的调用同样适用于子类】
  • 依赖倒置 【高层次的模块不应该依赖于低层次的模块】
  • 接口隔离 【不应强迫客户端实现一个它用不上的接口,或是说客户端不应该被迫依赖它们不使用的方法】

继承

继承是面向对象一个特点,可以实现子类调用自己没有的属性方法【父类属性方法】

/** ES6 **/
class Parent {}
class Child extends Parent { constructor () { super() } }
/** ES5 **/
function parent () { this.run () {} }
parent.prototype.eat = function () {}
function child () {}
// 原型式继承
child.prototype = parent.prototype
child.prototype.constructor = child
// 原型链继承
child.prototype = new parent()
child.prototype.constructor = child
// 构造器继承
function boyChild (..arg) { parent.apply(this, arg) }
// 组合继承
function boyChild (..arg) { parent.apply(this, arg) }
boyChild.prototype = new parent()
child.prototype.constructor = child
// 寄生组合继承
function child (..arg) { parent.apply(this, arg) }
// ${1}
(
  function () {
    function transmit () {};
    transmit.prototype = parent.prototype
    child.prototype = new prototype()
    child.prototype.constructor = child
  }
)()
// ${2}
child.prototype = Object.create(parent.prototype)
// ......
// 总结
// 继承的方式方法多种多样,不外乎,就是通过,某一种方式将不属于自己的属性方法可以调用,沿着原型的方式和拷贝赋值就可以总结出很多种不同的继承方式,每种方式的优缺点,多是考虑,继承的属性方法的完整性和对实例化对象的影响,如实例上方法和原型链上方法是否都可以调用有或者引用传递改变同一原型链问题。
/** 上面为对实例对继承,下面说一说对于接口对继承 **/
// ES6 中并没有提供接口这个概念,但是 Typescript 中对于接口又很好对支持,typescript 是 javascript 对超集,对面向对象提供了非常好对支持
// Typescript 【一时用一时爽,一直用一直爽】
// 很推荐用这个,他能避免很多低级错误,提供类型检查,特别是写过 java 转前端的。
interface parent { run: () => void }
class child implements parent { run () {} }
// 转码后
var child = /** @class */ (function () {
    function child() {
    }
    child.prototype.run = function () { };
    return child;
}());

多态

多态是面向对象一个特点,可以实现子类有不同对表现形态,可以实现同一种表现形式,可以有不同对状态

/** ES6 **/
// ${1} 重写
class Animal {
  eat () { console.log('animal eat') }
}
class Pig extends Animal {
  constructor () { super() }
  eat () { console.log('pig eat grass') }
}
class Tiger extends Animal {
  constructor () { super() }
  eat () { console.log('tiger eat pig') }
}
// ${2} 重载,模拟实现
class Animal {
  eat () {
    if (typeof arg === '') {
      console.log('操作 one')
    } else if (typeof arg === '') {
      console.log('操作 two')
    } else {
      console.log('操作 three')
    }
  }
}
/** ES5 【提供实现一种】**/
// 原理就是沿着原型链往上找,只要在父类前定义重写这个方法即可
// ${1} 重写
function animal () { this.eat = function () { console.log('Animal eat') } }
function pig () {
  animal.call(this)
  this.eat = function () { console.log('pig eat grass') }
}
function tiger () {
  animal.call(this)
  this.eat = function () { console.log('tiger eat pig') }
}
// ${2} 重载
function animal () {
  eat () {
    if (typeof arg === '') {
      console.log('操作 one')
    } else if (typeof arg === '') {
      console.log('操作 two')
    } else {
      console.log('操作 three')
    }
  }
}

封装

封装是面向对象一个特点,将属性和方法封装这对象中,可以利用私有或者公有属性,对外提供可以访问的方法或属性

/** ES6 **/
// ES6 没有提供真正的私有方法和属性,有一个还在提案阶段
// 在属性和方法前面加 #
class Animal {
  #height = ''
  #eat () {}
}
// 模拟实现 【提供一种实现】
class Animal {
  constructor () { this.height = '50' }
  get height() { return undefined }
  set height (value) { return undefined }
}
/** ES5 **/
const animal = (function (arg) {
  let height = 50
  function eat () {console.log(height)}
  return { eat }
})([])
/** Typescript **/
class Animal {
  public height: number
  private name: string
  protected color: string
  constructor (height: number, name: string, color: string) {
    this.height = height
    this.name = name
    this.color = color
  }
  private eat ():void { console.log(this.name) }
}

函数编程编程(FP)

函数式编程提倡函数是第一公民【指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值】,纯粹的函数式编程,是纯函数【如果传入的参数相同,就会返回相同的结果,不依赖于外部的数据状态【如下实例】】,函数编程特点

// 纯函数
const add = (one, two) => { return one + two }
// 非纯函数
let two = 1
const add = (one) => { return one + two }
  • 闭包和高阶函数
  • 柯里化
  • 偏函数
  • 组合和管道
  • 函子

闭包和高阶函数

闭包理解 函数内部还有其他函数,可以使父函数数据状态得以保存 高阶函数理解 函数可以通过变量传递给其他函数

// 利用封包实现一个只能调用一次的 map 高阶函数
const map = (fn) => {
  let once = false
  return (arr) => { return once? null: (once = true, arr.map(fn)) }
}
const fn = (item) => item + 10
const arrMap = map(fn)
arrMap([1, 2, 3]) // [11, 12, 13]
arrMap([4, 5, 6]) // null

柯里化

柯里化理解 柯里化是将一个多元函数转换为嵌套一元函数的过程

function curry (fn) {
  return curryN (...arg) {
    if (arguments.length < fn.length) {
      return function () {
        return curryN.call(null, ...arg.concat(...arguments))
      }
    }
    return fn.call(null, ...arguments)
  }
}
const add = curry ((x, y, z) => x + y + z)
console.log(add(2)(3)(4)) // 9

偏函数

偏函数理解 初始化时指定原函数的一些参数并创建一个新函数,这个函数用于接收剩余参数

function proto(fn, ...pagram) {
  return (...args) => {
    args.forEach((item, index) => { if (item && !pagram[index]) pagram[index] = item })
    return fn.apply(null, pagram)
  }
}
let add = proto((x, y) => { console.log(x + y) }, undefined, 10)
add(2) // 12

组合和管道

组合和管道理解 将一个函数的输出作为另一个函数的输入,像流水一样从函数队列从左到右流动或者从右到左流动

// 单个参数,简单组合
const compose = (fn, fnc) => (arg) => fn(fnc(arg))
// 多个参数,借助偏函数实现
function mapArr(arr, fn) { return arr.map(fn) }
function filte (arr, fn) { return arr.filter(fn) }
let map = proto(mapArr, undefined, (item) => { return item + 10 })
let filter  = proto(filte, undefined, (item) => { return item })
let mapFilter = compose(map, filter)
console.log(mapFilter([1, false, 9, 4])) // [11, 19, 14]
// 多个函数组合
const reduce = (arr, fn, value) => {
  let initValue = value? value: arr[0]
  arr.forEach((item) => { initValue += fn(initValue, item) })
  return initValue
}
const compose = (...arg) => (value) => reduce(arg.reverse(), (acc, fn) => fn(acc), value)
let add = compose(() => { return 1 }, () => { return 2 }, () => { return 3 })
add(6) // 12

函子

函子的定义 函子是一个普通对象(在其他语言中,可能是一个类),它实现了 map 函数,在遍历每个对象值的时候生成一个新对象 很抽象,简单来说 函子是一个持有值的容器。嗨难懂,上代码。

  • 如图[网上所盗]

// 实现一个基本定义的函子,满足定义
// 实现 map 方法,在遍历对象的时候生成一个新对象
function container (value) { this.value = value }
container.prototype.of = function (value) { return new container(value) }
container.prototype.map = function(fn) { return new container().of(fn(this.value)) }
new container().of([1, 5, 7, 3]).map((arr) => { return arr.filter((item) => item === 5)})
console.log(
  new container().of([1, 5]).map((arr) => { return arr.filter((item) => item === 5)}).value
) // 5

写在最后

到此面向对象和函数式编程的基本思想就都简单实现了,更多的需要自行深入学习

上面两种编程方式在学习实践的过程中给我提供了很多解决问题和组织代码框架的思维,在很多开源库中也能看见它们实现的影子,当然真正理解这两种编程方式,谈何容易,更多的是要不断的实践和思考总结,慢慢积累

https://github.com/loo41/Blog

以上就是js面向对象编程OOP及函数式编程FP区别的详细内容,更多关于js面向对象OOP函数式FP区别的资料请关注我们其它相关文章!

(0)

相关推荐

  • JS实战面向对象贪吃蛇小游戏示例

    目录 思考 一.贪吃蛇效果图 二.贪吃蛇分析 2.1 开始游戏功能 2.2 运动功能 2.2.1 蛇的不同方向的运动 2.2.2 键盘控制方向运动功能 2.3 吃食物功能 2.3.1 食物的产生 2.3.2 吃食物的过程 2.4 死亡判定功能 2.4.1 触边死亡判断(撞墙了) 2.4.2 自己撞到自己 2.5 暂停/继续游戏功能 总结 思考 第一步思考蛇分为几个部分,蛇头和蛇身体是怎么形成的. 第二步思考蛇是怎么运动的:如何通过键盘控制蛇的走向. 第三步思考游戏在什么情况下会结束. 第四步思考

  • JS中的一些常用的函数式编程术语

    组合 Composition 组合某种类型(含函数)的两个元素,进而生成一个该类型的新元素: JavaScript let compose = (f, g) => a => f(g(a)) let toUpperCase = x => x.toUpperCase() let exclaim = x => x + '!' let shout = compose(exclaim, toUpperCase); shout("hello world") // HELLO

  • javascript函数式编程基础

    目录 一.引言 二.什么是函数式编程 三.纯函数(函数式编程的基石,无副作用的函数) 四.函数柯里化 五.函数组合 六.声明式和命令式代码 七.Point Free 八.示例应用 九.总结 一.引言 函数式编程的历史已经很悠久了,但是最近几年却频繁的出现在大众的视野,很多不支持函数式编程的语言也在积极加入闭包,匿名函数等非常典型的函数式编程特性.大量的前端框架也标榜自己使用了函数式编程的特性,好像一旦跟函数式编程沾边,就很高大上一样,而且还有一些专门针对函数式编程的框架和库,比如:RxJS.cy

  • JavaScript函数式编程(Functional Programming)组合函数(Composition)用法分析

    本文实例讲述了JavaScript函数式编程(Functional Programming)组合函数(Composition)用法.分享给大家供大家参考,具体如下: 组合(Composition)函数,就是把两个或以上的函数组合到一块儿,整成一个新的函数.我找到了一个很好的例子,很好地解释了组合函数这个概念. 比如一个应用主要是记录一下日常的花销(expenses),应用里的数据看起来像这样: const expenses = [ { name: '租金', price: 3000, type:

  • JavaScript面向对象实现放大镜案例

    本文实例为大家分享了JavaScript面向对象实现放大镜的具体代码,供大家参考,具体内容如下 效果图 实现原理分析 如图所示 触发鼠标的移动事件时,根据事件对象的 clientX 和 clientY 属性得到实时的坐标点 x 和 y 值 ,减去 small_box 的 offsetLeft 值 和 cutting_box 的宽度的一半 ,可以得到 cutting_box 的偏移量 left 值,top值同理.当 cutting_box 到达右侧和下侧时,left 和 top 取得最大值.用 实

  • JavaScript实现简易轮播图最全代码解析(ES6面向对象)

    本文实例为大家分享了JavaScript实现简易轮播图的具体代码,供大家参考,具体内容如下 完整代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>ES6轮播图</title> <script></script> <style> * { margin: 0; padding: 0; } .box { wi

  • js面向对象编程OOP及函数式编程FP区别

    目录 写在前面 javscript 中函数和对象的关系 面向对象编程(OOP) 继承 多态 封装 函数编程编程(FP) 闭包和高阶函数 柯里化 偏函数 组合和管道 函子 写在最后 写在前面 浏览下文我觉得还是要有些基础的!下文涉及的知识点太多,基本上每一个拿出来都能写几篇文章,我在写文章的过程中只是做了简单的实现,我只是提供了一个思路,更多的细节还是需要自己去钻研的,文章内容也不少,辛苦,如果有其他的看法或者意见,欢迎指点,最后纸上得来终觉浅,绝知此事要躬行 javscript 中函数和对象的关

  • Java函数式编程(一):你好,Lambda表达式

    第一章 你好,lambda表达式! 第一节 Java的编码风格正面临着翻天覆地的变化. 我们每天的工作将会变成更简单方便,更富表现力.Java这种新的编程方式早在数十年前就已经出现在别的编程语言里面了.这些新特性引入Java后,我们可以写出更简洁,优雅,表达性更强,错误更少的代码.我们可以用更少的代码来实现各种策略和设计模式. 在本书中我们将通过日常编程中的一些例子来探索函数式风格的编程.在使用这种全新的优雅的方式进行设计编码之前,我们先来看下它到底好在哪里. 改变了你的思考方式 命令式风格--

  • JavaScript与函数式编程解释

    作者:月影 牢记:函数式编程不是用函数来编程!!!23.4函数式编程  23.4.1 什么是函数式编程 什么是函数式编程?如果你这么直白地询问,会发现它竟是一个不太容易解释的概念.许多在程序设计领域有着多年经验的老手,也无法很明白地说清楚函数式编程到底在研究些什么.函数式编程对于熟悉过程式程序设计的程序员来说的确是一个陌生的领域,闭包(closure),延续(continuation),和柯里化(currying)这些概念看起来是这么的陌生,同我们熟悉的if.else.while没有任何的相似之

  • 用函数式编程技术编写优美的 JavaScript

    级别: 初级 Shantanu Bhattacharya (shantanu@justawordaway.com), 首席顾问, Siemens Information Systems Limited 2006 年 7 月 20 日 函数式或声明性编程是非常强大的编程方法,正逐渐在软件行业流行起来.这篇文章将介绍一些相关的函数式编程概念,并提供有效使用这些概念的示例.作者将解释如何使用 JavaScript(TM)(JavaScript 能导入函数式编程的构造和特性)编写优美的代码. 简介 函数

  • JS函数式编程实现XDM一

    盲猜一个:如果你有看过 <medium 五万赞好文-<我永远不懂 JS 闭包>> <“类”设计模式和“原型”设计模式——“复制”和“委托”的差异> 这两篇文章,你一定会对 JS 的[函数]有更多兴趣! 皮一下,很舒服~ 没错!JS 就是轻量级的函数式编程! 拆解一下这句话,品味一下~ 本瓜将借助<JavaScript 轻量级函数式编程>一书带领你先透析它的落脚点函数式编程,然后再看看 JS 为什么被称为是 “轻量的”! 此篇是<JS如何函数式编程>

  • JS面向对象编程基础篇(一) 对象和构造函数实例详解

    本文实例讲述了JS面向对象编程对象和构造函数.分享给大家供大家参考,具体如下: 面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式.它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟.每一个对象都是功能中心,具有明确分工,可以完成接受信息.处理数据.发出信息等任务.对象可以复用,通过继承机制还可以定制.因此,面向对象编程具有灵活.代码可复用.高度模块化等特点,容易维护和开发,比起由一系列函数或指令

  • JS面向对象编程基础篇(二) 封装操作实例详解

    本文实例讲述了JS面向对象编程封装操作.分享给大家供大家参考,具体如下: Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果我们要把"属性"(property)和"方法"(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢? 封装 一. 生成实例对象的原始模式 假定我们把猫看成一个对象,

  • JS函数式编程之纯函数、柯里化以及组合函数

    目录 前言 纯函数 纯函数的概念 副作用 纯函数案例 柯里化 柯里化的概念 函数柯里化的过程 函数柯里化的特点及应用 自动柯里化函数的实现 组合函数 前言 函数式编程(Functional Programming),又称为泛函编程,是一种编程范式. 早在很久以前就提出了函数式编程这个概念了,而后面一直长期被面向对象编程所统治着,最近几年函数式编程又回到了大家的视野中,JavaScript是一门以函数为第一公民的语言,必定是支持这一种编程范式的. 下面就来谈谈JavaScript函数式编程中的核心

  • JS面向对象编程详解

    序言 在JavaScript的大世界里讨论面向对象,都要提到两点:1.JavaScript是一门基于原型的面向对象语言 2.模拟类语言的面向对象方式.对于为什么要模拟类语言的面向对象,我个人认为:某些情况下,原型模式能够提供一定的便利,但在复杂的应用中,基于原型的面向对象系统在抽象性与继承性方面差强人意.由于JavaScript是唯一一个被各大浏览器支持的脚本语言,所以各路高手不得不使用各种方法来提高语言的便利性,优化的结果就是其编写的代码越来越像类语言中的面向对象方式,从而也掩盖了JavaSc

  • JS面向对象编程实现的Tab选项卡案例详解

    本文实例讲述了JS面向对象编程实现的Tab选项卡.分享给大家供大家参考,具体如下: Tab选项卡案例 下面是一个简单面向过程的Tab选项卡. <!DOCTYPE html> <html> <head> <style> #tabBox input { background: #F6F3F3; border: 1px solid #FF0000; } #tabBox .active { background: #E9D4D4; } #tabBox div { w

随机推荐