Giter Site home page Giter Site logo

blog's People

Contributors

lampkid avatar

Stargazers

 avatar

Watchers

 avatar  avatar

blog's Issues

React Native的入坑研究笔记

研究要点

RN之前需要了解的?

React/Redux
Flexbox layout

Typescript/flow/babel/metro bundler
Static Analysis:Eslint/prettier

Android/iOS knowledge
DLS:Design Language System

RN需要学习的

  1. philosophy
    Cross-Platform
  2. RN RUNTIME: JSCore
  3. debugging/hot reloading
  4. SharedElement transitions
  5. Lottie
  6. Animations
  7. Crash Monitoring
  8. Native Bridge: communicate between native and RN
  9. Gestures
  10. Long lists: FlatList/RecycleView/UICollectionView

RN需要关注的

Performance
flexbox engine :yoga
App Size
Initialization Time: runtime initialization
Initial Render Time
RN upgrading
Accessiblity

正文

React Native的诞生

React Native的哲学

什么时候该考虑React Native

不同团队对RN的态度是不一样,有经验的团队自然会觉得RN很赞,自然也有团队会后悔使用RN。

使用RN中可能遇到的挑战

  • RN本身还不稳定,发展变化很快。
  • 使用RN一方面要构建RN工程化体系,一方面要开发新特性。
  • 开发环境和生产环境调试方法偶尔不一致。开发环境需要同时维护三套包括RN、iOS、Android。
  • 遇到问题时,我们很难知道这是由于哪个团队造成的,还是RN本身的bug导致的。
  • RN要有非常好的用户体验,要求开发人员对各种平台都很了解。有时候需要写一些native组件,有时候调试问题时,会跟进到native本身上。移动端团队构建上并不能完全脱离Android、iOS工程师。
  • 团队决策:团队招聘是否需要招聘native工程师、不同团队怎么合作、native、RN、h5间如何共享app状态、如何保证跨平台调试、如何保证整个app的测试质量、如何决定使用哪个平台开发新功能等等。

我们使用RN想达到什么目标,RN是否能满足?RN是否适合你的团队

  • 迭代快
  • 统一的质量标准
  • 多平台,写一套代码
  • 提升开发体验、包括构建、调试等
  • Native App中混合RN
  • 工程师专长

参考

React Native in airbnb

持续集成

问题汇总

  1. 持续集成中,我们经常会在脚本文件里拷贝文件。拷贝文件里会有一些坑
  • 拷贝到不存在的目录:此时应该加-p选项
  • 保留原有文件的属性:比如软连接的拷贝。Mac上用-R选项。Linux上用-d选项
  1. 软连接拷贝的一个例子
    一个node项目里,该项目依赖安装在当前项目根目录的node_modules目录,

git 规范

git commit message

commitizen
conventional-changelog
conventional-changelog-cli
cz-conventional-changelog
npx commitizen init cz-conventional-changelog --save-dev --save-exact
conventional-changelog -p angular -i CHANGELOG.md -w
npx git-cz
package.json
 "config": {
     "commitizen": {
       "path": "./node_modules/cz-conventional-changelog"
     }
   }

经验文集再读笔记

写在前面的话
—— 俞敏洪

我们人的生活方式有两种,第一种方式是像草一样活着。你尽管活着每年还在成长,但是你毕竟是 一棵草,你吸收雨露阳光,但是长不大,人们可以踩过你,但是人们不会因为你的痛苦而他产生痛苦, 人们不会因为你被踩了而来怜悯你,因为人们本身就没有看到你。所以我们每个人都应该像树一样的成 长,即使我们现在什么都不是,但是只要你有树的种子,即使被人踩到泥土中间,你仍然能够吸收泥土 的养分自己成长起来,当你长成参天大树以后,遥远的地方人们就能看到你,走近你。你能给人一片绿 色,活着是美丽的风景,死了依然是栋梁之才,活着死了都有用。这就是我们每一个人做人的标准和成 长的标准。

每一条河流都有自己不同的生命曲线,但是每一条河流都有自己的梦想,那就是奔向大海,我们的 生命有的时候会是泥沙,你可能慢慢地就会像泥沙一样沉淀下去了,一旦你沉淀下去了,也许你不用再 为了前进而努力了,但是你却永远见不到阳光了,所以不管你现在的生命是怎样的一定要有水的精神, 像水一样不断地积蓄自己的力量,不断地冲破障碍但你发现时机不到的时候,把自己的厚度给积累起 来,当有一天时机来临的时候,你就能够奔腾入海,成就自己的生命!

  • 编写程序判断一个数是否为水仙花数
  • 高等数学引论 华罗庚版本 https://item.jd.com/13546476448.html
    是否可以重新学习下高等数学
  • 谭浩强的《C语言程序设计教程》看一遍,做一遍习题,再学习一遍C语言
    或者用JS或Python或Go实现
  • 北大张筑生先生的《数学分析新讲》https://item.jd.com/10523336914.html
  • 科学出版社的 《数学史教程》京东上没找到
    学习一门学科,不能不了解它的历史
  • 数学与计算科学
    数学为精确处理是什么提供了一种方法,而计算则 为精确处理怎样做提供了一个手段
  • 计算机组成原理
    祖冲肖讲的一本书,没找到相关信息
  • 计算机文化
    书名:New Perspective on Computer Concepts ,https://item.jd.com/11470688.html
    通过该书可以了解计算机科学各领域分支,从总体上认识上计算机科学
    关注整个计算科学的发展史和计算机科学的内涵与外延两个问题。

最近想写几篇关于技术实战的文章

第一:基于React的项目搭建和框架设计和实战

第二:基于React的国际化项目实战

第三: 基于Koa的Node项目设计和实战。

基于React的项目搭建和框架设计和实战

这篇主要包括两个模块:

  • 项目基本框架的搭建和本地开发环境与流程的搭建
  • 信息管理系统模块的配置化实战

项目基本框架

  • 基本流程和规范 (git、eslint、docs)
  • 本地环境: mock server、hot update、webpack构建
  • 分包和异步加载
  • 菜单和路由配置化
  • 整体页面布局(菜单、面包屑、个人中心)
  • 状态管理机制
  • 基于React Hooks的开发模式的讨论
  • SSR支持

信息管理系统的配置

  • 表单配置化的设计与实现
  • 表格的配置化设计与实现
    • 表格数据的格式化渲染
    • 表格操作的规范定义

Topics

  • 富文本编辑器

  • JSX ->JSON JSON->JSX->HTML

  • JSX ->HTML->Canvas->PDF生成

redux & vuex

- vuex redux
store count 1 1
action method object
action trigger dispatch dispatch
data processor mutation handler reducer
trigger data processor commit mutation dispatch action
get data this.$store&mapState&getter -
process dispatch->action->commit mutation->mutation handler -> state-change->getter dispatch->action->reducer->state change->connect
module modules & register modules redux(combine reducers)
async saga mutaion sync,action async
action intercept plugin middleware

React internals-学习React的设计理念

最近团队发起了React源码解读的分享,分享过程中大家对一些问题也讨论了很多,各执己见。由于之前团队很少做类似的分享,所以在React这么一个大型项目源码解读时,是没有方向和茫然的。分享过程中,自己梳理了几个问题。记录以备后续研究。

分享思路:

  • React版本变化的影响:解读过程中,需要确定大前提,我们是基于React的哪个版本,讨论它的设计。
  • 概念性认知:在解读过程中,先解释本次话题中涉及到的概念,利于听者的认知理解。
  • 抽象举例:从某一个demo举例,说明React的某个涉及理念,只要能说明原理,不一定贴React里的源码。

技术话题:

  • React中transaction事务的概念,是为了解决那哪些问题的, 举例说明使用场景

  • setState的原理,是异步的还是同步的,分别有哪些场景

  • setTimeout回调中setState处理方式,eventloop参与的过程

  • 批量更新的原理,在事件处理的中是批量更新的,在生命周期中也是批量更新的吗?

  • 有setTimeout时,断点调试还有用吗

参考:

React官网关于内部实现的文章和设计原则
mattgreer-react-internals
Under-the-hood-ReactJS

中间件的设计与应用

本文会从多个实际应用中的中间件实现 分析中间件的设计和实现。比如redux、Django、koa2等

redux中间件

// https://github.com/reduxjs/redux/blob/master/src/applyMiddleware.js

/**
 * Composes single-argument functions from right to left. The rightmost
 * function can take multiple arguments as it provides the signature for
 * the resulting composite function.
 *
 * @param {...Function} funcs The functions to compose.
 * @returns {Function} A function obtained by composing the argument functions
 * from right to left. For example, compose(f, g, h) is identical to doing
 * (...args) => f(g(h(...args))).
 */

export default 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)))
}


/**
 * Creates a store enhancer that applies middleware to the dispatch method
 * of the Redux store. This is handy for a variety of tasks, such as expressing
 * asynchronous actions in a concise manner, or logging every action payload.
 *
 * See `redux-thunk` package as an example of the Redux middleware.
 *
 * Because middleware is potentially asynchronous, this should be the first
 * store enhancer in the composition chain.
 *
 * Note that each middleware will be given the `dispatch` and `getState` functions
 * as named arguments.
 *
 * @param {...Function} middlewares The middleware chain to be applied.
 * @returns {Function} A store enhancer applying the middleware.
 */
export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

koa2中间件

// https://github.com/koajs/koa/blob/master/lib/application.js
// https://github.com/koajs/compose/blob/master/index.js
'use strict'

/**
 * Expose compositor.
 */

module.exports = compose

/**
 * Compose `middleware` returning
 * a fully valid middleware comprised
 * of all those which are passed.
 *
 * @param {Array} middleware
 * @return {Function}
 * @api public
 */

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  /**
   * @param {Object} context
   * @return {Promise}
   * @api public
   */

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

参考

https://medium.com/@meagle/understanding-87566abcfb7a

weex研究

weex研究

初步了解weex

weex playground

weex基本架构和基本原理

架构

js framework原理

https://mp.weixin.qq.com/s/K6wXSGPywc7Ltm0T3lz-Sg

开发

weex集成到现有App

本地开发环境搭建

本地web调试

本地模拟器调试

真机调试

开发框架和语言

Vue

样式

尺寸

布局

逻辑

JavaScript

组件

组件库

扩展组件

路由

weex如何绑定到原生View

weex内部路由

weex-vue-render

通信

weex与原生通信

weex与H5通信

跨weex页面通信

js service

基本的工具库

兼容性问题

比如iPhoneX尺寸兼容

体验优化

比如下拉刷新

Demo实践

发布与上线

刷版管理

降级H5

线上容错

出现错误,如何自动降级或下线

线上监控

数据上报

lodash的debounce和自己实现的debounce深入对比思考

背景:最近做一个商品库的项目时,需要一个实时搜索功能。当用户在输入框输入关键字时,实时根据关键字搜索结果。

问题:使用lodash.debounce时,特别是输入汉字时,当用户删除输入的内容时,删除的体验上不是很流畅,有点硌得慌。后续附上一个code demo。

解决方案:使用自己实现的debounce完美解决。

分析:lodash的debounce和自己实现的debounce到底有什么区别?

hook的应用

Hook、钩子,一种**或者说是设计模式,有很多应用。比如Wordpress的hook、sequenlize中hook的应用、React Hooks等。

错过成长的场景

安全产品

  1. 分布式架构实践
  2. 数据库性能优化
  3. 大屏数据可视化
  4. 完整的一套包括配置、配置消费、插件机制、插件调度、结果反馈(明细展示、全局可视化、告警)、结果验证、知识库、二次开发能力的系统。
  5. 半自动化扫描(登录扫描)

电商平台

  1. 电商C端从商品列表->商品详情->购物车 ->下单->支付的全套流程以及转化漏斗模型
  2. 电商B端商品发布平台和商品API自助接入平台
  3. 评价->关注->IM->点赞的能力
  4. H5生成平台

midway

  1. Node的实战:包括中间层模板支持、登录和鉴权、接口转发、接口聚合、SSR、Serverless等
  2. CMS配置化平台

监控

  1. 前端监控
  2. 日志监控
  3. 硬件监控

上传与下载文件的原理

本文我们用Node来讨论文件上传与下载的问题。
利用Node中提供的各种库来谈谈文件上传与下载

web开发中需要深入理解的知识点

一次团队分享中讨论的话题点,在此备忘。

topic

  1. layout: inline-block(不同div间存在空白-设置父节点font-size为0. vertical-align: top. baseline;
  2. media:viewport:了解视口
  3. meta:meta用来做什么的?有哪些meta?浏览器是怎么解释meta的
  4. dpr
  5. 0.5rem: 0.5rem的实现,如何判断当前设备是否支持0.5px
  6. rem & image: image使用rem展示会产生什么问题
  7. rem & html font-size & body font-size:为什么用rem时要设置body的font-size
  8. pix2rem & rem2pix: 开发中如何选用pix和rem,如果互相转化。
  9. pageshow/pagehide:如何处理前进/后退事件
  10. throttle & debounce
  11. 手淘flexible库

参考

https://quirksmode.org/mobile/viewports.html

2017~2018专题总结

媒体上传

表单项

灵活的表单布局方案设计

规则链

JSON Diff的两种方案

Node web框架 koa的二次封装

拖拽-从原生到三方库

微信公众号文章消息

发布流程的UI设计

JSON schema在模板、数据校验、mock等的应用

crud方案

webpack在前端工程的应用以及项目结构设计

你不知道的git

作为程序员,更准确地说,我们用程序员地身份做着码农的事情。我们只是技术的使用者和搬运工。
作为软件开发工程师,我们只是在用前端开发或PHP工程师的一维角度去做着自己该做的事情,没有软件和软件开发的全局观
作为一个程序员,我们只是把技术作为纯粹的工具做事情。而我们却说,我们技术很厉害,我很精通JS、PHP、JAVA等。
作为前端开发人员,本身对业务,即对自己所做的事情本身不是很熟悉,对自己使用到的技术也只是使用。最后技术和业务两空空。
作为工程实践人员,我们也要有些学术型思维,去了解去研究技术本身,提升自己的深度。学术与工程不冲突。

今天分享下你所不知道的git

参考

聊聊UniqId

很多场景中我们都需要标记一条数据的唯一性,我们把标记这条数据的唯一性的标记称为uniqId,这个uniqId也可称为key。

uniqId的生成

如何保证uniqId的唯一性?

  • time
  • device
  • ip
  • mac addr
    ...

作为一个非纯粹的前端工程师和Node工程师,应该了解的技术栈

本文以软件开发工程师和Node角度来看,我们应该了解哪些知识?

需要了解的基本知识

Linux
Git
HTTP:Cookie

需要了解的设计模式

MVC:设计模式
模块规范:AMD/CMD/UMD/ module 、namespace
中间件**

需要了解的组件

Nginx:web服务器,静态资源访问和反向代理、负载均衡
redis/memcache:缓存
MySql/MongoDB: 数据存储
elasticSearch:全文检索
Kafka/MQ:消息队列

需要了解一些运维知识

Devops
SRE
Docker
k8s

安全

安全:基本的漏洞、安全产品、安全开发、安全运维

JS中类的实现

引子

开始之前,先说下为什么会研究这个问题?
在分析别人的node代码,比如express、koa等时,发现了两种不同定义路由方法或者我们称之为action的方案。

静态方法

function MyController() {
}
MyController.doAction = function() {
}

对象方法

class MyController {
  doAction() {
  }
}
const ctrl = new MyController()

两种方案都在实际生产中有实践。要分析两种方案的优劣和区别,得先了解class方案实际上是怎么实现的。
然后从内存、性能、写法等多方面可以考量。

本文不讨论何种方案优劣,只作为本篇文章的引子!

正文

  • 此处只讨论babel中是如何实现的!(此处我们更应该了解node怎么实现class?)

研究路径:
定义一个类->定义一个类的方法->定义一个类的静态方法->定义一个类的属性->定义一个类的静态属性->私有属性的实现(不讨论)->私有方法的实现(不讨论)->继承一个类。

先写一个最简单的空类

源码

class MyClass {
}

babel编译

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var MyClass = function MyClass() {
  _classCallCheck(this, MyClass);
};

分析

定义一个类,实际上定义了一个函数,只是比普通函数多了一个实例检查,判断该实例是否是通过构造函数创建的。一般我们创建一个类的实例使用new MyClass()关键字。

定义一个类的方法

源码

定义一个doAction方法

class MyClass {
  doAction() {
    console.log('do something...');
  }
}

babel编译

"use strict";

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false; // 是否可枚举,如for ... in , Object.keys
      descriptor.configurable = true;   // 是否可配置
      if ("value" in descriptor) descriptor.writable = true; // 是否可修改
      Object.defineProperty(target, descriptor.key, descriptor); // 通过defineProperty定义类的方法
    }
  }
  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps); // 原型属性定义
    if (staticProps) defineProperties(Constructor, staticProps);    // 静态属性定义,下面再讨论。
    return Constructor;
  };
} ();

function _classCallCheck(instance, Constructor) {
  if (! (instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var MyClass = function() { // 类通过一个立即执行函数包裹并返回
  function MyClass() { // 定义构造函数,并验证实例是否正确。
    _classCallCheck(this, MyClass);
  }

  _createClass(MyClass, [{ // 通过_createClass方法定义类的方法
    key: "doAction",
    value: function doAction() {
      console.log('do something...');
    }
  }]);

  return MyClass;
} (); 

分析

  1. 类通过一个立即执行函数包裹并返回
  2. 定义构造函数MyClass,并调用_classCallCheck函数验证实例是否正确
  3. 通过_createClass函数定义类的方法
  • 着重分析下_createClass函数的实现
    我们可以看到,_createClass函数主要通过Object.defineProperty重写了构造函数的原型属性和静态属性。
    重中之重,我们只要了解Object.defineProperty就一目了然了。具体可以参考MDN
    实际上,定义一个方法本质上是利用Object.defineProperty在一个对象上定义了一个描述符descriptor。
    一个描述符可以有configurable、writable、enumerable、value、get、set属性。

configurable: 为true时,a.可删除该属性; b. 可配置除描述符的writable属性之外的属性,如enumerable、get、set、value等
writable:为true时,才可通过赋值改变定义属性的值,否则只读
enumerable:当为true时,才可通过for ... in ,Object.keys获取到定义的属性。
get\set,当读取一个属性或给一个属性赋值时,get/set会自动执行。很多现代js框架数据和dom绑定的核心原理。

定义一个类的静态方法

源码

class MyClass {
  doAction() {
    console.log('do something...');
  }
  // 静态方法
  static doStaticAction() {
    console.log('do something static');
  }
}

babel编译

'use strict';

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }
  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps); // here
    return Constructor;
  };
} ();

function _classCallCheck(instance, Constructor) {
  if (! (instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var MyClass = function() {
  function MyClass() {
    _classCallCheck(this, MyClass);
  }

  _createClass(MyClass, [{
    key: 'doAction',
    value: function doAction() {
      console.log('do something...');
    }
  }], [{
    key: 'doStaticAction', // here,_createClass的第三个参数
    value: function doStaticAction() {
      console.log('do something static');
    }
  }]);

  return MyClass;
} ();

解释

我们可以在_createClass函数中发现:

    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps); // here

普通方法和静态方法唯一的区别在于:方法是定一个在了构造函数的原型上还是构造函数本身。
我们知道。我们调用一个类的普通方法时,我们需要实例化。而调用静态方法时,可直接用类名直接引用调用。如MyClass.doStaticAction()

定义一个类的属性和静态属性

源码

class MyClass {
  
  prop = 1;  // 定义一个实例属性
  static staticProp = 2; // 定义一个静态属性
  
  doAction() {
    console.log('do something...');
  }
  static doStaticAction() {
    console.log('do something static');
  }
}

babel编译

'use strict';

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }
  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
} ();

function _classCallCheck(instance, Constructor) {
  if (! (instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var MyClass = function() {
  function MyClass() {
    _classCallCheck(this, MyClass);

    this.prop = 1;  // 定义的实例属性
  }

  _createClass(MyClass, [{
    key: 'doAction',
    value: function doAction() {
      console.log('do something...');
    }
  }], [{
    key: 'doStaticAction',
    value: function doStaticAction() {
      console.log('do something static');
    }
  }]);

  return MyClass;
} ();

MyClass.staticProp = 2; // 定义的静态属性

解释

是不是发现了什么不一样的东东。
为什么方法和静态方法通过Object.defineProperty定义的,而属性和静态属性不一样了?
为什么没有把prop属性定义到构造函数的prototype上?
为什么没有通过Object.defineProperty将staticProp定义到构造函数constructor上?
如果采用和定义方法同样的方法Object.deifneProperty定义属性和静态属性会发生什么?

要解答这些问题,其实我们可以从《Javascript权威指南》中找到答案:

Javascript类相关的对象有三个:
构造函数对象:如在引文中提到的MyController.doAction,定义在构造函数对象中的属性都是类字段和类方法。即定义在了Constructor上。
原型对象:原型对象上的属性被类的所有实例所共享,Object.defineProperty(Constructor.prototype, doAction),即定义在了prototype上。
实例对象: 在实例对象上的属性只在实例上生效,如其中的属性MyClass中的prop,不会为所有实例所共享,即定义在了this上。

理解了上面三个对象,上面的问题自然迎刃而解。

写一个空类继承MyClass

源码

class MyClass {
  
  prop = 1;
  static staticProp = 2;
  
  doAction() {
    console.log('do something...');
  }
  static doStaticAction() {
    console.log('do something static');
  }
}

class MyChildClass extends MyClass {
}

babel编译

'use strict';

var _createClass = function() {
  function defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }
  return function(Constructor, protoProps, staticProps) {
    if (protoProps) defineProperties(Constructor.prototype, protoProps);
    if (staticProps) defineProperties(Constructor, staticProps);
    return Constructor;
  };
} ();

function _possibleConstructorReturn(self, call) {
  if (!self) {
    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  }
  return call && (typeof call === "object" || typeof call === "function") ? call: self;
}

function _inherits(subClass, superClass) {
  if (typeof superClass !== "function" && superClass !== null) {
    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
  }
  subClass.prototype = Object.create(superClass && superClass.prototype, {
    constructor: {
      value: subClass,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

function _classCallCheck(instance, Constructor) {
  if (! (instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var MyClass = function() {
  function MyClass() {
    _classCallCheck(this, MyClass);

    this.prop = 1;
  }

  _createClass(MyClass, [{
    key: 'doAction',
    value: function doAction() {
      console.log('do something...');
    }
  }], [{
    key: 'doStaticAction',
    value: function doStaticAction() {
      console.log('do something static');
    }
  }]);

  return MyClass;
} ();

MyClass.staticProp = 2;

var MyChildClass = function(_MyClass) {
  _inherits(MyChildClass, _MyClass); // 调用_inherits实现继承

  function MyChildClass() {
    _classCallCheck(this, MyChildClass);

    return _possibleConstructorReturn(this, (MyChildClass.__proto__ || Object.getPrototypeOf(MyChildClass)).apply(this, arguments));  // 构造函数比父类MyClass多了一个返回
  }

  return MyChildClass;
} (MyClass);

解释

从上面可以看到,引入了继承,一切看起来不再那么简单。
不过总体来说,子类继承父类做了两个工作:

  1. 调用_inherits继承父类
  2. 构造函数调用 _possibleConstructorReturn返回原型实例

下面主要研究这两个函数具体是怎么做的?
当然还有一个很明显的问题,为什么父类在构造函数里不需要返回,而子类构造函数需要返回?
下面逐一分析。

  1. _inherits
  • 父类校验,一个类的父类要么是一个函数,要么这个类没有父类。
  • 调用Object.create用父类的原型重写子类的原型prototype
  • 将子类的__proto__属性指向父类
  1. _possibleConstructorReture
    这个待讨论
    从以上分析,我们可以归纳出,继承需要的几个要素:
  • 原型重写
  • __proto__重写
  • 构造函数重写

说到这里,可能还是不太明白?
为了彻底搞明白继承这个事情,我们必须先了解下面几个问题:

  1. 理解prototype与__proto__的区别
  2. 什么是原型链
  3. 原型继承怎么做?

待续?

这些我们可以另开文章注意研究讨论。

其实这个问题我们还可以继续讨论,如:
如果给子类添加新的属性或新的方法,是如何编译的?
如果有一个孙子类继承子类,又是如何编译,和父类MyClass的关系又如何?

总结

上面我们可以说基本上都是以研究的思路一点一点逐步加深的思路去做的?
我会在另一篇文章里以总结的思路去重新梳理这篇文章?
比如:

  • 研究这个问题之前,我们需要具备哪些基础?
  • 有了上面的基础,我们先从整体上去看待类和面向对象的概念?
  • 了解了类和面向对象的概念,我们就可以用前面提到的基础聊聊js中特有的类和面向对象,并可以和其他语言做一个对比。
  • 最后从整体上梳理整篇文章阐述时前后各种概念的关系。

Node框架中的目录结构设计

generator-koa-rest

image

generator-koa

.
├── app.js     // 各种中间件和bootstrap,路由的聚合也在这个文件里,只有一级路由
├── controllers  // controllers
│   └── messages.js 
├── package.json
├── public    // 静态文件
│   ├── scripts
│   └── styles
│       └── main.css
├── test // unittest
│   └── routeSpec.js
└── views  template
    ├── layout.html
    └── list.html

generator-k

.
├── app.js  各种中间件以及路由中间件入口 bootstrap
├── config 各类环境的配置信息
│   ├── config.js
│   └── local.js
├── controller
│   └── index.js
├── log 
├── model 
├── package.json
├── public
│   ├── css
│   └── js
├── router // 具体路由映射controller
│   └── index.js
├── test
│   └── index-router-spec.js
└── view 模板
    ├── index.xtpl
    └── layout
        ├── footer.xtpl
        ├── header.xtpl
        └── layout.xtpl

node-koa-api

https://github.com/mjhea0/node-koa-api

.
├── LICENSE
├── README.md
├── knexfile.js 数据库配置信息
├── package.json
├── src
│   └── server
│       ├── auth.js 用户登录认证
│       ├── db
│       │   ├── connection.js // 创建数据库连接
│       │   ├── migrations // 数据表设计
│       │   │   ├── 20170817152841_movies.js
│       │   │   └── 20171231115201_users.js
│       │   ├── queries // 数据库DAO
│       │   │   ├── movies.js
│       │   │   └── users.js
│       │   └── seeds
│       │       ├── movies_seed.js
│       │       └── users.js
│       ├── index.js // app路由、中间件、启动
│       ├── routes // 不同模块的路由文件
│       │   ├── _helpers.js
│       │   ├── auth.js
│       │   ├── index.js
│       │   └── movies.js
│       ├── session.js session redis存储
│       └── views 模板
│           ├── admin.html
│           ├── login.html
│           ├── register.html
│           └── status.html
└── test
    ├── integration
    │   ├── routes.auth.stub.test.js
    │   ├── routes.auth.test.js
    │   ├── routes.index.test.js
    │   └── routes.movies.test.js
    └── unit
        └── sample.test.js

egg

> https://github.com/eggjs/examples/tree/master/sequelize

├── README.md
├── README.zh-CN.md
├── app
│   ├── controller controller
│   │   ├── post.js action
│   │   └── user.js
│   ├── extend  // 扩展
│   │   └── helper.js
│   ├── model // 数据表定义与DAO
│   │   ├── post.js
│   │   └── user.js
│   ├── router.js // 路由聚合
│   └── service // 服务层,调用model的DAO完成业务层逻辑
│       ├── post.js
│       └── user.js
├── config // 配置信息
│   ├── config.default.js
│   ├── config.unittest.js
│   └── plugin.js
├── database // 数据库配置信息
│   ├── config.json
│   └── migrations
│       ├── 20180813112934-user.js
│       └── 20180813112942-post.js
├── package.json
└── test
    ├── app
    │   ├── controller
    │   │   ├── post.test.js
    │   │   └── user.test.js
    │   └── service
    │       └── post.test.js
    └── factories.js

yog2

.
├── LICENSE
├── README.md
├── app
│   └── README.md
├── app.js
├── conf
│   ├── plugins
│   │   ├── dispatcher.js
│   │   ├── http.js
│   │   ├── log.js
│   │   ├── ral.js
│   │   ├── recv-reload.default.js
│   │   ├── reqlimit.js
│   │   └── views.js
│   └── ral
│       └── demo.js
├── home
│   ├── client
│   │   ├── page
│   │   │   ├── index.tpl
│   │   │   └── layout.tpl
│   │   ├── static
│   │   │   └── js
│   │   │       ├── README.md
│   │   │       ├── bigpipe.js
│   │   │       ├── index.js
│   │   │       ├── lazyload.js
│   │   │       ├── mod.js
│   │   │       └── page.js
│   │   └── widget
│   │       └── message
│   │           └── message.tpl
│   ├── fis-conf.js
│   ├── package.json
│   └── server
│       ├── action
│       │   ├── book.js
│       │   └── index.js
│       ├── lib
│       │   └── util.js
│       ├── model
│       │   └── index.js
│       └── router.js
├── package.json
├── plugins
│   └── README.md
├── static
└── views

总结

  • app : middlewares, bootstrap,可考虑将通用方法挂载到ctx上。
  • routes: 多级路由dispatch,一级路由为不同的模块,即controller类名,二级路由为action,即action方法名
  • controllers: 控制器,不同模块编写不同的类函数
  • service: controller调用服务层完成具体业务逻辑,service调用下游model层中的DAO完成具体数据库操作
  • model 数据表定义
  • DAO :可作为service下的子目录
  • config 环境配置、app配置
  • database 数据库配置
  • RAL: 后端数据访问层,HttpClient,reqlimit
  • middlewares/plugins:log,auth,
  • views:模板、视图

数据库设计遇到的那些问题

数据表设计中,ID应该使用数据表中自增id还是应该设计一个业务ID?

比如图书系统中,book表,应该直接用自增id作为book记录的唯一id还是设计一个book_id字段用于表示book记录的唯一性?

比如订单表,order表中,order_id字段的设计?

使用自增主键是否总是最佳实践?

数据库表之间关联关系应该如何设计?

比如老师和学生,其之间的关联关系设计有以下两种方法:

  1. 设计teacher和student两张表,在student表中增加teacher_id字段表示其之间的关联关系
  2. 设计三张表,teacher、student、rel_teacher_student, 在rel_teacher_student里表示teacher和student之间的关联关系。
    哪种在实践中更好呢?我们应该选哪种?

三级关联关系中,冗余设计是否合理?

比如供应商、店铺、商品,供应商可以将商品供应给多家店铺,多家店铺售卖多个商品,我们表字段应该如何设计?

数据库多表查询时,使用join查询还是查询多次

数据库查询时,in和or的效率问题

使用where id in [1, 2] 还是 使用where id = 1 or id =2

数据库与ORM时区Timezone问题

数据库 timezone的处理以及engine/ORM对timezone的处理

在NodeJS使用sequelize时,sequelize设置时区为+8:00,存储数据为当前时间,没有问题。
当使用sequelize查询结果时,查询的结果早了8小时。

数据库状态字段设计中,审核状态和生效停用状态用一个字段还是两个字段?

一个字段:比如用status表示审核通过或失败,通过后,如果启用status变为启用
两个字段:用status表示审核状态,用active表示是否生效

权限设计,以防逻辑越权漏洞

事务操作

索引和unique设计

索引根据查询字段组合设计

数据表里有name,title,description字段,根据一个关键字query 做or查询,这个需要建索引吗?建单列索引还是联合索引? select * from table where name like '%a%' or title like '%a' or description like '%a';
最左原则

前端方向与专题选择

专题

数据可视化

  • 炫酷的动画
  • canvas
  • 数据分析
  • 报表

拖拽

窗口、viewport尺寸、DOM尺寸、事件位置等

定位与布局

CMS

CMS工厂

H5

登录SDK
H5工厂

Hybrid

H5调用Native能力的JS SDK

小程序

性能优化

H5离线客户端缓存
Bigpipe
SSR

大前端

Node领域的大前端

客户端领域的大前端

  • RN
  • Weex

业务能力

该部分均为平台性质的,且平台具有开放性

Portal

微前端

前端的app store

组件库建设

工程化建设

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.