前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《The Joy of Javascript》- 1 - Object/Function

《The Joy of Javascript》- 1 - Object/Function

作者头像
szhshp
发布2022-09-21 10:42:51
2120
发布2022-09-21 10:42:51
举报
文章被收录于专栏:szhshp 的第四边境中转站

关于此书 - 从此我给别人面试可以出究极难度的题目了 😏

早先在 Github 看到人提起这本书, 我简单翻了一下目录, 发现有一些内容还挺有意思, 里面有很多近几年的新方法, 正好补充一些之前开发未涉及的部分.

本以为两三周可以阅读完毕, 没想到啃这本书真是困难, 引用了数学分析和函数式的概念, 一些部分看得我一脸懵逼, 额外阅读了大量的 Funtional Programming 的文章才得以吃掉这本书.

从此我给别人面试可以出究极难度的题目了 😏

相关文章

一本书里面内容较多, 因此分成了多篇 Post, 可以从此处看到相关文章:

Object

通过使用 mixin 实现对象继承

Mixin 模式的优势:

  1. 支持多继承
  2. 可以对现有的对象添加独立的方法, 这些方法可以在多个对象里面复用
Mixin 实现多继承
代码语言:javascript
复制
const TerrestrialAnimal = {
  walk() {},
  breathe() {
    console.log("Using my lungs to breathe");
  },
};

const AquaticAnimal = {
  swim() { },
  breathe() {
    console.log("Using my gills to breathe");
  },
};

const Amphibian = (name) =>
  Object.assign(
    {
      name,
    },
    AquaticAnimal, /* Using my gills to breathe */
    TerrestrialAnimal  /* Using my lungs to breathe */
  );

const frog = Amphibian("Frog");

frog.walk();
frog.swim();
frog.breathe(); /* Using my lungs to breathe */
OLOO(Objects-linked-to-other-objects) 模式对象扩展
代码语言:javascript
复制
/* HasHash 返回一个含有 calculateHash 方法的对象 */
const HasHash = (keys) => ({ /* keys 接受一个字符串数组 */
  calculateHash() {
    const data = keys.map((f) => this[f]).join(""); /* 注意此处会获取 this 里面的属性 */
    let hash = 0,
      i = 0;
    while (i < data.length) {
      hash = ((hash << 5) - hash + data.charCodeAt(i++)) << 0;
    }
    return hash ** 2;
  },
});

const Transaction = {
  init(sender, recipient, funds = 0.0) {
    this.sender = sender;
    this.recipient = recipient;
    this.funds = Number(funds);
    return this;
  },
  displayTransaction() {
    return `Transaction from ${this.sender} to ${this.recipient} for ${this.funds}`;
  },
};



/* 核心代码, 通过 Object.create 创建一个对象并绑定 this, 同时使用 Object.assign 对对象进行扩展 */
const HashTransaction = Object.assign(
  Object.create(Transaction),  
  HasHash(["sender", "recipient", "funds"])
);




const t = HashTransaction.init("Alice", "Bob", 100.0);
console.log(t.calculateHash());  // 620300900133850900
console.log(t.displayTransaction()); // Transaction from Alice to Bob for 100
Class 模式对象扩展
代码语言:javascript
复制
const DEFAULT_ALGO_SHA256 = 'SHA256';
const DEFAULT_ENCODING_HEX = 'hex';

const HasHash = (
  keys,
  options = {
    algorithm: DEFAULT_ALGO_SHA256,
    encoding: DEFAULT_ENCODING_HEX
  }
) => ({
  calculateHash() {
    const data = keys.map(f => this[f]).join('');
    let hash = 0, i = 0;
    while (i < data.length) {
      hash = ((hash << 5) - hash + data.charCodeAt(i++)) << 0;
    }
    return hash ** 2;
  }
})

class Transaction {
  transactionId = '';
  timestamp = Date.now();
  #feePercent = 0.6;
  constructor(sender, recipient, funds = 0.0, description = 'Generic') {
    this.sender = sender;
    this.recipient = recipient;
    this.funds = Number(funds);
    this.description = description;
    this.transactionId = this.calculateHash();  /* 特别注意这个地方调用了 calculateHash, 并且 calculateHash 不是 Transaction 自带的方法 */
  }
  displayTransaction() {
    return `Transaction ${this.description} from ${this.sender} to 
 ${this.recipient} for ${this.funds}`;
  }
  get netTotal() {
    return Transaction.#precisionRound(
      this.funds * this.#feePercent, 2);
  }
  static #precisionRound(number, precision) {
    const factor = Math.pow(10, precision);
    return Math.round(number * factor) / factor;
  }
}


/* 在扩展前直接实例化会报错: TypeError: this.calculateHash is not a function, 因为 Transaction 自身还没有这个方法 */
// const t1 = new Transaction('Mike', 'Jack', 10.0, 'Generic');  




/* 核心代码 */
/* 通过 Object.assign 将 HasHash Mixin 扩展到 Transaction 里面 */
Object.assign(
  Transaction.prototype,
  HasHash(['timestamp', 'sender', 'recipient', 'funds']),
  // HasSignature(['sender', 'recipient', 'funds']),
  // HasValidation()
)




/* 此时进行实例化就可以调用 HasHash 返回的 calculateHash 方法 */
const t2 = new Transaction('Mike', 'Jack', 10.0, 'Generic');
console.log(t2.transactionId); 

Function

函数式编程和 OOP 的比较 | FP vs OOP | Differences between FP and OOP

Functional Programming

OOP

Does not exist State

Exists State

Uses Immutable data

Uses Mutable data

It follows Declarative Programming Model

It follows Imperative Programming Model

Stateless Programming Model

Stateful Programming Model

Main Fcous on: "What you are doing"

Main focus on "How you are doing"

Good for Parallel (Concurrency) Programming

Poor for Parallel (Concurrency) Programming

Good for BigData processing and analysis

NOT Good for BigData processing and analysis

Supports pure Encaspulation

It breaks Encaspulation concept

Functions with No-Side Effects

Methods with Side Effects

Functions are first-class citizens

Objects are first-class citizens

Primary Manipulation Unit is "Function"

Primary Manipulation Unit is Objects(Instances of Classes)

Flow Controls: Function calls, Function Calls with Recursion

Flow Controls: Loops, Conditional Statements

It uses "Recursion"concept to iterate Collection Data.

It uses "Loop"concept to iterate Collection Data. For example:-For-each loop in Java

Order of execution is less importance.

Order of execution is must and very important.

Supports both "Abstraction over Data"and "Abstraction over Behavior".

Supports only "Abstraction over Data".

We use FP when we have few Things with more operations.

We use OOP when we have few Operations with more Things. For example: Things are classes and Operations are Methods in Java.

功能编程

面向对象

不存在状态

存在状态

使用不可变数据

使用可变数据

它遵循声明式编程模型

它遵循命令式编程模型

无状态编程模型

有状态编程模型

主要观点: "你在做什么"

主要关注"你的表现"

适合并行 (并发) 编程

并行 (并发) 编程能力差

适用于 BigData 处理和分析

不适合 BigData 处理和分析

支持纯封装

它打破了包容性概念

无副作用的功能

副作用方法

职能是一等公民

对象是一等公民

主要操作单元是"功能"

主要操作单位是对象 (类的实例)

流控制: 函数调用, 带递归的函数调用

流控制: 循环, 条件语句

它使用"递归"概念来迭代收集数据.

它使用"循环"概念来循环收集数据. 例如: Java 中的 for-for 循环

执行顺序不太重要.

执行顺序是必须且非常重要的.

支持"基于数据的抽象"和"基于行为的抽象".

仅支持"基于数据的抽象".

当我们的事物很少且需要更多操作时, 我们将使用 FP.

当我们很少进行具有更多事物的操作时, 我们将使用 OOP. 例如: 在 Java 中, 事物是类, 而操作是 Java 中的方法.

Functional Programming Example | 函数式编程示例

一个命令式编程的例子:

代码语言:javascript
复制
const arr = ['john-reese', 'harold-finch', 'sameen-shaw'];
const newArr = [];
for (let i = 0, len = arr.length; i < len ; i++) {
  let name = arr[i];
  let names = name.split('-');
  let newName = [];
  for (let j = 0, naemLen = names.length; j < naemLen; j++) {
  let nameItem = names[j][0].toUpperCase() + names[j].slice(1);
  newName.push(nameItem);
  }
  newArr.push({ name : newName.join(' ') });
}
return newArr;

一个函数式编程的例子:

代码语言:javascript
复制
const capitalize = x => x[0].toUpperCase() + x.slice(1).toLowerCase();

const genObj = curry((key, x) => {
  let obj = {};
  obj[key] = x;
  return obj;
}) 

// 使用 compose 将多个方法进行结合
const capitalizeName = compose(join(' '), map(capitalize), split('-'));
const convert2Obj = compose(genObj('name'), capitalizeName)
const convertName = map(convert2Obj);

convertName(['john-reese', 'harold-finch', 'sameen-shaw'])

FP 核心专注于以下几个方法:

  1. compose
  2. curry

使用这些方法可以对函数进行合成和连锁调用

主流三方库已经有类似实现, 比如 lodash 的 _.curry , _.flow. 甚至这些库还支持使用 _.curryRight , _.flowRight 来进行从右向左的执行顺序

compose 方法实现
代码语言:javascript
复制
function compose(……funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
 
  if (funcs.length === 1) {
    return funcs[0]
  }
 
  return funcs.reduce((a, b) => (……args) => a(b(……args)))
} 

使用方法:

代码语言:javascript
复制
const operate = compose(div2, mul3, add1, add1)
operate(0) // 相当于 div2(mul3(add1(add1(0)))) 
operate(2) // 相当于 div2(mul3(add1(add1(2))))
curry 方法的实现
代码语言:javascript
复制
export const curry = fn => (……args1) =>
  args1.length === fn.length
    ? fn(……args1)
    : (……args2) => {
      const args = [……args1, ……args2]
      return args.length >= fn.length ? fn(……args) : curry(fn)(……args)
    }

Summary

  • JavaScript offers many choices for building objects, including prototypal inheritance, constructor functions, and classes.
  • The phrase prototype inheritance is an oxymoron because the idea of a shared linked prototype object is contradictory to the class inheritance model, in which instances gain copies of the inherited data.
  • Constructor functions have been the standard mechanisms used to mimic the idea of classes in JavaScript.
  • Classes smooth over the details of the prototype configuration for newcomers or developers coming from other class-based languages and have become the preferred choice of JavaScript developers.
  • The class syntax can blur your understanding of JavaScript』s prototype inheritance mechanism. Classes are useful, but remember that JavaScript is different from other class-based languages you may have seen or used.
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关文章
  • Object
    • 通过使用 mixin 实现对象继承
      • Mixin 实现多继承
      • OLOO(Objects-linked-to-other-objects) 模式对象扩展
      • Class 模式对象扩展
  • Function
    • 函数式编程和 OOP 的比较 | FP vs OOP | Differences between FP and OOP
      • Functional Programming Example | 函数式编程示例
      • compose 方法实现
      • curry 方法的实现
  • Summary
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档