分类: tech

  • 重新学习JavaScript(1)

    学习JavaScript,就从MDN开始,其中包含了大量的值得深入学习和理解的内容。在这篇博客我介绍一些最近看到的。

    1,class expression

    首先就是类表达式https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/class 说实话这是我最近才知道的用法。它的语法如下,非常类似正常的类定义语句(class declaration statement),但是可以赋值给一个变量。如果使用typeof查一下就知道,MyClass类型还是function

    const MyClass = class [className] [extends otherClassName] {
        // class body
    };

    类表达式可以重复定义,这个和类定义方式不同。另外className可以省略,如果命名了,那这个名字也只在class body有效,这个和function expression是一样的 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function

    2, this

    this在JavaScript面试中几乎是必考的点,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this 这里值得注意的几点,一个是call和apply怎么记忆呢?最简单的办法就是apply第二个参数接受的是数组类型,也就是array,a对a就能容易记住了。

    下面这段代码,其中有个知识点就是如果第一个参数不是object类型,就会调用内部的ToObject函数,比如7就会变成Number,而字符串字面值‘foo’就会转成String。

    function bar() {
      console.log(Object.prototype.toString.call(this));
    }
    bar.call(7);     // [object Number]
    bar.call('foo'); // [object String]

    而bind需要注意的是只会绑定一次

    function f() {
      return this.a;
    }
    var g = f.bind({a: 'azerty'});
    console.log(g()); // azerty
    var h = g.bind({a: 'yoo'}); // bind only works once!
    console.log(h()); // azerty

    3,Destructuring assignment解构赋值

    这个词有点难理解,多看看里面的示例会好很多,大致上分成两类数组解构和对象解构 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

    下面这个用法有点费解,最后得到的两个变量不是a和b,而是aa和bb。

    const {a: aa = 10, b: bb = 5} = {a: 3};
    console.log(aa); // 3
    console.log(bb); // 5

    继续加深理解

    const user = {
      id: 42,
      displayName: 'jdoe',
      fullName: {
        firstName: 'John',
        lastName: 'Doe'
      }
    };
    function userId({id}) {
      return id;
    }
    function whois({displayName, fullName: {firstName: name}}) {
      return `${displayName} is ${name}`;
    }
    console.log(userId(user)); // 42
    console.log(whois(user));  // "jdoe is John"

    注意与下面的例子的区别,主要在参数的声明格式上。一个用的等号,一个用的冒号。

    function drawChart({size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}) {
      console.log(size, coords, radius);
    }
    drawChart({
      coords: {x: 18, y: 30},
      radius: 30
    });

    这个例子更复杂些,属性是计算得来

    let key = 'z';
    let {[key]: foo} = {z: 'bar'};
    console.log(foo); // "bar"

    还可以用rest 属性… 顺序也没有关系,只要能和属性名对上就行

    let {c, a, ...rest} = {a: 10, b: 20, c: 30, d: 40}
    a; // 10
    c; // 30
    rest; // { b: 20, d: 40 }
    const foo = { 'fizz-buzz': true };
    const { 'fizz-buzz': fizzBuzz } = foo;
    console.log(fizzBuzz); // "true"

    数组解构和对象解构组合起来

    const props = [
      { id: 1, name: 'Fizz'},
      { id: 2, name: 'Buzz'},
      { id: 3, name: 'FizzBuzz'}
    ];
    const [,, { name }] = props;
    console.log(name); // "FizzBuzz"
  • 在JavaScript中应用Mixin模式

    编程中Mixin是什么?我最近看到这个词,有点感兴趣起来。我以前也见过这个词,依稀记得是在介绍Ruby的文章当中,但是JavaScript中的Mixin干什么用呢?有些公众号提到express.js和vue.js的实现应用了mixin模式,我最近主要也是做这些方面,所以得关注了解啊。

    最权威的还是先看看wiki怎么说:https://en.wikipedia.org/wiki/Mixin 头一段说明有点绕,不是很容易理解,那就看看JS代码吧。Wiki列出了三种实现,分别是extend,Object.assign以及Flight-Mixin。

    第一种extend方式的参考实现,就是把源对象上面的key,逐个赋值到目标对象上。其它的两种大致也都是如此,Flight-Mixin模式其实就是IIFE直接执行的变形。

    剥掉了神秘感,剩下的就很简单了。有什么限制呢?首先,mixin的源对象操作this的属性,一定要在目标对象上存在,否则就会出现undefined问题了。其次mixin在JS这种动态类型的编程语言是合适的,如果用在c#这样的静态类型语言,就可以用扩展方法来实现,更灵活的就得用dynamic来定义this了。

    那mixin的用处,大致就是mixin源对象可以定义behavior,然后可以动态的绑定到其它对象上,只要这些对象满足mixin的constraints就可以了,把行为抽象出来。就此推论,mixin也很容易实现成decorator。mixin还要注意的一点是,它实质是一种浅拷贝,浅拷贝可能有的问题它也会有。

    在core-decorators项目中的代码更加完整 https://github.com/jayphelps/core-decorators/blob/5b754256a30c23a0aef846c1b45f261e0c7b21a2/src/mixin.js,其中使用了getOwnPropertyDescriptors以及defineProperty这样更为特定的函数处理不同的情况。

    mixin有什么问题么?当然有,什么设计模式都有局限性和适用的场景。比如react就提到https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html 简单说,mixin在大的codebase中增加了隐形依赖复杂度(Mixins introduce implicit dependencies),命名冲突问题(Mixins cause name clashes),滚雪球复杂度(Mixins cause snowballing complexity)。所以在express.js这样的轻量级框架中使用mixin说的通,但是复杂的企业级应用,就不得不考虑复杂度带来的各种问题。

    我的建议是如果软件超过7个人开发,那就考虑angular/TypeScript/rxjs这一套。如果是小项目,可以考虑react或者vue.js,但是最好也配上babel加ES最新标准。

    感兴趣的可以留言讨论。

  • 通过awesome和alternative学技术

    编程技术学习到某个程度,就需要扩展眼界,这样才能把自己锻造成T字形人才,有深度有广度。

    我这里推荐两个方法可以扩展某个领域的知识面,一个是Awesome,一个是alternative。

    比如我想了解更多关于angular方方面面的知识,可以直接在github敲入awesome angular搜索,就可以找到这个repo https://github.com/PatrickJS/awesome-angular 如果感兴趣rust,就能找到https://github.com/rust-unofficial/awesome-rust 。Awesome类知识汇集有点类似百科全书,或者是以前的dmoz(还有人知道这个么?),有空就可以瞅瞅,对于某个项目/库感兴趣了就深挖一下。

    alternative的用法又不一样了。我经常收到领导的要求,其实也是架构师常见的工作,就是比较不同产品或者框架的优缺点,做一些比较或者雷达图什么的。这时候就可以搜索关键字加“alternative”,比如想了解aws的竞争者就在谷歌搜“aws alternative”,然后点开结果页面看看。还有一个网站https://alternativeto.net/ 就是专门做同类型软件比较打分的,还算客观。

  • 周末玩玩技术

    我很久以前玩过一段时间的google appengine,用它来连接rss填补google reader的空白。前两天趁着周末又捡出来把玩了一下,现在的感觉却不怎么好用了,难怪google的云计算赶了个大早,却被后来者azure居上。

    简单的crud应用,比如todo或者记事本甚至是proxy,appengine还是可以用一用的。但是它有几个问题,一个是standand环境的编程比较复杂,开发者要了解一大堆东西,总算把google datastore在nodejs上跑了起来,但是运行起来才发现javascript版本的rss parser不给力,不如python的feedparser成熟。而python想找一个在appengine稍微能用的blog或者cms几乎是不可能的,大多数的github项目都是11、12年甚至零几年的。另外的问题是如果不付费很多功能都阉割了,即使google cloud赠送了300美元一年的试用,可是我不想浪费时间在这个没落的平台上了。

    于是又想到了新型的平台zeitnetlify,它俩都支持连接到github直接拽代码部署,命令行直接搞定,试用了一下部署一个coreui的angular demo棒棒哒。如果是纯js项目可以考虑这两个平台。

    做toy project的开发者还可以考虑heroku,这个老牌平台虽然有着google cloud同样的缺点,但是它上面一些开源项目却很实用,比如部署了一个下载youtube视频的应用在上面,还可以支持v2,前面挂上cloudflare那就可以特殊情况下应应急。

  • 程序设计原则

    YAGNI – You Aren’t Gonna Need It
    https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
    https://martinfowler.com/bliki/Yagni.html
    “Always implement things when you actually need them, never when you just foresee that you need them.”
    “你不需要做这事”原则,但是也需要权衡短期就需要的灵活扩展可能性。
    建议:对于需求之外的扩展,可以经过小组讨论决定是否需要。

    Don’t repeat yourself
    https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
    “别重复自己”原则。
    通过自动化测试替代反复使用的手动测试。
    通过设计模式,抽象,继承,重载,公用函数来减少代码重复。
    提醒信号:再一再二,但不能再三再四。如果一件事,一段代码,一个需求,一个手动测试反复出现,就可以考虑应用DRY原则。

    KISS – Keep it simple, stupid
    https://en.wikipedia.org/wiki/KISS_principle
    “保持简单”原则。
    对于一个需求,如果有两种实现,一种较为简单,一种比较复杂,尽量选择简单的实现。
    参考“奥卡姆剃刀” (https://zh.wikipedia.org/wiki/%E5%A5%A5%E5%8D%A1%E5%A7%86%E5%89%83%E5%88%80 )

    If it ain’t broke, don’t fix it
    https://en.wikipedia.org/wiki/Bert_Lance#If_it_ain’t_broke,_don’t_fix_it
    “没坏就不修”原则。
    一个设计或者代码,虽然不够好,如果满足需求还能用就不要动它。
    反例:如果新的开发要修改以前代码,可以考虑一起把不够好的部分修掉。