一个数字截取引发的精度问题(四)

做前端的都感觉JS这语言巨坑无比,兼容性让你摸不到头脑。一些初学者遇到:

0.1 + 0.2 = 0.30000000000000004

都会觉得这JS太TM坑了,一个小数计算都不会。可是我想说,这”锅”JS不背!其实和JS采用的数值存储 IEEE754 规范有关,
所有采用此规范的语言都会有此问题并不是JS的”锅”。

IEEE754

IEEE浮点数算术标准(IEEE 754)是最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用,单精确度(32位)、双精确度(64位)、延伸单精确度(43位以上,很少使用)与延伸双精确度(79位元以上,通常以80位元实做)

计算机中是用有限的连续字节保存浮点数的。 JS采用64位(双精度)存储数据,在 IEEE 标准中,浮点数是将所有二进制位分割为特定宽度的符号域(S),指数域(E)和尾数域(F)三个域, 其中保存的值分别用于表示给定二进制浮点数中的符号,指数和尾数。

根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:

V = (-1)^s×M×2^E
  1. (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
  2. M表示有效数字,大于等于1,小于2,但整数部分的1可以省略。
  3. 2^E表示指数位。

    对于十进制的5.25对应的二进制为:101.01,相当于:1.0101*2^2。所以,S为0,M为1.0101,E为2。
    -5.25=-101.01=-1.0101*2^2。所以S为1,M为1.0101,E为2。

复习一下十进制转2进制

口诀

整数部分除2取余,由下到上;小数部分乘2取整,由上到下。

0.1 在计算机中如何存储?

首先 0.1 转化为二进制:0.000110011(0011循环)套用公式可得:

(-1)^0*1.1001*2^-4

所以 s:0,M:1.1001(循环1001),E:-4。

由于小数位仅储存 52bit, 储存时会将超出精度部分进行”零舍一入”,

无限精确值:

1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001

实际储存值:

1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010

此处精度已经丢失一次。最后0.1实际存储为:

0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010

同理计算出0.2的实际存储值(同样也存在精度丢失):

0.001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010

两数相加得:

0.01001100110011001100110011001100110011001100110011001110

再转为十进制:0.30000000000000004。

在线转换工具:http://tool.oschina.net/hexconvert。

参考:

https://www.web-tinker.com/article/20035.html

http://www.mallocfree.com/interview/c-5-float.htm

https://zh.wikipedia.org/zh-hans/%E4%BA%8C%E8%BF%9B%E5%88%B6

http://2ality.com/2012/04/number-encoding.html

http://zencode.in/1.%E6%B5%AE%E7%82%B9%E6%95%B0%E5%8A%A0%E5%87%8F%E9%97%AE%E9%A2%98.html

sass vs less

sass

2007年发布,最早的一款CSS预处理器,带来了变量、常量、嵌套、混入、函数、循环等功能,
解决了CSS不可编程的短板。由于浏览器不能直接识别Sass,所以需要预先编译。

Sass有两套语法规则:

  1. 缩进式
body
    color: red
    header
        background: red
  1. 大括号
body{
    color: red
    header{
        background: red
    }
}

less

2009年,受Sass影响,但使用的CSS语法,可以快速上手。它也有上面说的一些功能。

下面对比一些常用功能:

变量

变量是代码最小的复用单元,可以减少硬编码。

sass

$color: blue;

body{
    $color: black;
    color: $color;
}

less

@color: blue;

body{
    @color: black;
    color: @color;
}

提到变量,就不得不提作用域。

$color: black;
.scoped {
    $bg: blue;
    $color: white;
    color: $color;
    background-color:$bg;
}
.unscoped {
    color:$color;
}

sass在这里还是有点小问题的:

3.4.0之前:

.unscoped{
    color: white
}

之后:

.unscoped{
    color: black;
}

后声明的变量总是会覆盖之前声明的变量,不管之前变量在何处声明。也就是变量都是全局的,谁在后面谁是老大。

3.4.0(包括)之后,修正了这个问题:

All variable assignments not at the top level of the document are now local by default. If there’s a global variable with the same name, it won’t be overwritten unless the !global flag is used. For example, $var: value !global will assign to $var globally. This behavior can be detected using feature-exists(global-variable-shadowing).

大概:变量不再是全局,而默认是局部,除非给变量声明时,加上 !global。

less就没有这个问题,作用域很其像他编程语言。

嵌套

sass/less 官都提到了写出的样式和 HMTL 的结构更加相像,层级很明了。

html

<nav>
    <ul>
        <li>
            <a></a>
        </li>
    </ul>
</nav>

sass / less

nav{
    ul{
        li{
           a{

           } 
        }
    }
}

其实这样嵌套深了也不一样好,毕竟最后也会转换为CSS,会导致选择器很长,从性能、代码体积上都会有损失。个人认为 3 到 4 层嵌套
就可以了,或者上面的也可以写成:

nav{
    ul{

    }

    li{

    }

    a{

    }
}

混入

一个规则集合可以导入到另一个规则集合,或者可以说大块的代码复用。适用场景:我们在写 CSS3 时,要加很多前缀(当然现在有好多工具可以自动添加)。

sass

@mixin border-radius($radius:10px) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
}

.box { 
    @include border-radius(10px); 
}

less

.border-radius(@radius:10px){
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
      -ms-border-radius: @radius;
          border-radius: @radius;
}

.box{
    .border-radius(5px);
}

sass 有严格的声明和引用语法:@mixin,@include,而less 就松散很多,同时less还有个问题:

.mixin{
    color:red;
}

.other-mixin(){
    background:blue;
}

.class{
    .mixin;
    .other-mixin;
}

output

.mixin{
    color:red;
}

.class{
    color:red;
    background:blue;
}

就是你在使用 mixin 时,不加小括号会把 mixin 也输出。因为 less 的编译器不知道你是在声明
mixin 还是在声明普通的选择器。

函数

sass/less 都各自内置了一些函数:Color、String、List、Math、Type等

sass/less

@base: #f04615;
@width: 0.5;

.class {
   width: percentage(@width); // returns `50%`
   color: saturate(@base, 5%);
}

output

.class {
   width: 50%;
   color: #f6430f;
}

最好的例子应该是 REM 布局中的 px2rem 函数了:

$baseFontSize:100px !default;

@function px2rem( $px , $base-font-size: $baseFontSize ){
    @if (unitless($px)) {
        @return px2rem($px + 0px);

    } @else if (unit($px) == rem) {
        @return $px;
    }

    @return $px/($base-font-size) * 1rem;
}


.body{
    font-size:px2rem(100)
}

导入

sass/less

@import "reset.css"

@import "reset" // reset.less / reset.scss

运算

四则运算

+ - * /

sass

$conversion-1: 5cm + 10mm; // result is 6cm
$conversion-2: 2 - 3cm - 5mm; // result is -1.5cm

less

@conversion-1: 5cm + 10mm; // result is 6cm
@conversion-2: 2 - 3cm - 5mm; // result is -1.5cm

单位也是参与计算的

继承

sass

.message{
    border:1px solid #ccc;
}

.success{
    @extend .message;
    border-color:green;
}

.error{
    @extend .message;
    border-color:red;
}

output

.message, .success, .error {
    border: 1px solid #ccc;
}

.success {
    border-color: green;
}

.error {
    border-color: red;
}

less (1.4.0加入)

.message{
    border:1px solid #ccc;
}

.success{
    &:extend(.message);
    border-color:green;
}

.error{
    &:extend(.message);
    border-color:red;
}

output

.message, .success, .error {
    border: 1px solid #ccc;
}

.success {
    border-color: green;
}

.error {
    border-color: red;
}

注:extend 和 mixin 有时可以达到同样的功能,但是从语法和输出后的代码上还是有些区别的。

extend生成的代码更紧凑、更符合预期。

全栈工程师指南

根据 Stack Overflow 2016年开发者调查显示,全栈工程师是最欢迎的开发者职业。毫无疑问现在有许多在线或个人课程来帮助程序员成为全栈开发者,甚至帮助这些开发者找到高薪的开发工作。

一些流行的在线课程,例如:Lynda,Udacity,Coursera,Thinkful,General Assembly 。除了这些在线课程,还有好多个人的新手训练营来提供给web开发者必须的技能。

在这篇文章中我不会讨论哪个在线或个人课程好,相反我会提供一个我认为成为全栈web开发者所需技能的权威指南。我将以下面三条为基准开始这篇博文:

  1. 2017年教给学生最多的课程是什么
  2. 我为公司面试开发者和有潜力的全栈开发者的经验
  3. 在 Coderbyte 接受新手训练,然后找到开发工作的开发者们的故事和反馈

权威指南

全栈工程师指既能开发前端又能开发后端的开发者。前端一般指一个应用中用户能看到和交互的部分,后端一般指一个应用中处理逻辑、数据库、用户授权、服务端配置等的部分。全栈工程师并不意味着你有必要完全掌握前后端的开发技术,而是你可以在构建应用时明白前后端开发到底发生了什么。

如果你想成为一名全栈开发者同时想得到一份工作,下面就是你应该学习的参考指南。

1.HTML/CSS

许多在线和个人课程都以HTML/CSS作为成为一名 web 开发者的开端,因为它俩是web开发的基石。HTML是网站内容的骨架,CSS是为网站内容美化的。下面是一些真实工作中和面试时经常需要的HTML/CSS内容:

  1. 语义化HTML
  2. 解释 CSS Box Model
  3. CSS 预处理器的优点(你并不需要深入了解,但是你应该知道它解决了什么问题和如何帮助开发者的)
  4. CSS Media Queries 解决不同屏幕和书写响应式CSS代码
  5. Bootstrap(一个CSS框架,事实上相对于Bootstrap的特点和方法,更重要的是对CSS基础知识的掌握)

2.JavaScript

每年 JavaScript 都变得越来越流行同时新的库、框架和工具都在持续不断的涌现。依据 2016 Stack Overflow 的调查,JavaScript 成为全栈、前端、后端开发的最流行语言。它是唯一一个既可以在浏览器运行又可在后端运行的语言。下面是你成为一个全栈开发所需要了解的内容:

  1. 知道如何处理DOM,同时也知道JSON是什么以及如何维护它。
  2. functional composition、prototypal、inheritance、closures、event delegation、scope、higher-order functions的一些语言特点
  3. 异步流程控制、promises和callbacks
  4. 学习如何架构你的代码同时抽取模块,了解webpack、browserify或者类似的gulp等构建工具如何帮助开发
  5. 最少了解一个流行框架(许多课程关注在一些库、框架上例如React、AngularJS,但事实上深入了解JavaScript更重要,一旦你对JavaScript有个很好的理解,然后再挑选一个框架从全局来看,你就不会感觉到有什么困难)
  6. 即使有些人在争论jQuery现在使用的很少或者它在渐渐的消亡,可是现在依旧有许多使用它构建的应用,实实在在的掌握jQuery依旧是很有帮助的
  7. 了解一些测试框架同时也应意识到测试为何如此重要
  8. 学习一些ES6的新特性

3.Back-End Language

一旦你感觉对HTML/CSS和JavaScript掌握的很好,你将需要学习一些处理数据库操作、用户鉴权、应用逻辑的后端语言。一些课程和新手训练营通常会专注一门特定的语言,但是随着你对后端开发的套路越来越清晰的时候,其实选择哪门语言已经不重要。如果你问不同的人,哪个后端语言适合学习会得到不同的答案,所谓仁者见仁智者见智。无论你选择哪个都要坚持学下去,不要三天打鱼两天晒网。下面是不同语言工作的需求量:

. Nodejs:这是一个不错的选择因为它本来就是JavaScript,所以你不需要学习一个新的语言。这也是一些在线培训和新手训练营选择Nodejs的一些原因。Express是Nodejs中一个很重要的框架可以帮助你开发web应用。

. Ruby:一些流行的开发框架,例如:Rails和Sinatra。相当多的课程已将Ruby作为第一后端开发语言。

. Python:其中的流行开发框架,例如:Django和Flask。

. Java:当谈及全栈开发的时候,Java并不会被经常提到,但是一些公司依旧在使用Java作为他们的后端语言同时也是一个需求量很大的语言。

. PHP:现在很少有教PHP的,但是它和JAVA一样需求量依旧存在。

4.Databases & Web Storage

当你在构建一个web应用,需要存储一些将来要使用的数据时,你应当掌握下面有关databases和storage的一些知识:

. 掌握关系型数据库,例如:SQL.

. 学习非关系型数据库,例如:MongoDB.

. 明白不同场景应该使用哪种。

. 掌握后端语言如何和数据库连接(Nodejs+MongoDB)

. 掌握像Redis和memcached的缓存好处

. 掌握像session,cookies和cached data浏览器端的数据存储

. 扩展数据库:ACID和ORM

5.HTTP & REST

HTTP是一个允许客户端连接服务器的无状态协议(例如JavaScript可使用AJAX发起一个HTTP请求)。下面就是你需要掌握的清单:

. 什么是REST以及为何它对HTTP和web应用如此重要?

. 设计REST API的最佳实践

. 学习使用Chrome DevTools

. 什么是SSL Certificates

. HTTP/2 & SPDY

. WebSockets,Web Workers和 Service Worders

6.Web Application Architecture

一旦你既掌握了前端技术又掌握了后端语言,同时数据库玩的也很溜,接下来最困难的东西在等着你。这时你若创建一个有点复杂的应用,就需要知道如何架构你的代码,如何分隔你的文件,在哪存储大体量的音频文件,如何设计你的数据库,在哪端执行有点计算量的任务(客户端vs服务端),当然还有更多需要考虑的。

你可以在网上读到许多最佳实践,但是最好的方法是自己创建一个大点的应用,或更好一点的是参与到一个团队中开发一个大型的应用。

这就是为何,一名具有7+年开发经验的人并不一定比只有2年经验的人对CSS和JavaScript有更好的理解。但是这些年他们参与开发了许多不同种类的应用和网站,同时也学习了如何构建和设计应用,以便在需要开发的时候更有效率和掌控全局。下面就是一些架构应用需要用到的知识:

. 学习公共平台服务(Heroku,AWS)。Heroku使你发布代码和构建应用非常方便,AWS提供了许多产品和服务需要的存储、视频处理、负载等等

. 应用和现代浏览器的性能优化

. 一个web应用应该包括哪些部分的意见

. 微软的 设计web应用指南

. MVC

. 最重要的是要在项目中和其他开发人员一起工作,在GitHub上学习别人的代码,同时从高级开发者那里尽可能的多学习。

7.Git

Git是一个版本管理系统,允许开发者追踪代码的所有更改记录。为了能提交、拉取以及解决代码冲突等,你显然需要学习一些Git背后的概念同时也要自己把玩。

. 这里是一些git命令的参考指南

. 这有一个为初学者准备的Git和GitHub教程

8.Basic Algorithms & Data Structure

这个主题在开发者世界中有点存在两极化,因为有些开发者认为像计算机科学例如:tree traversal,sorting,algorithm analysis,matrix manipulation,在web开发中并不应该过分的关注。但是一些大公司例如Googley依旧会在他们的面试中提问算法相关的问题,就像一些人关于Google前端工程师的说法:

我们的前端工程师希望有一些扎实的CS背景,就像其他工程师一样。

同时一些公司需要候选人拥有计算机科学学位或同等学位,当然也有一些公司不需要候选人有相关证书,只要能证明可以开发应用和对相应领域有所了解就可以。但是为了成为一名有实力的开发者,为了不写出低效的代码,或为了避免只因了解一点基础的算法和数据结构而使用错误的工具,同时为了能视情况作出权衡,所以下面列出了一些你应该学习的东西:

. 学习并深入了解hash tables,这种数据结构在JavaScript中使用对象表示(Python中为字典,Ruby中是哈希)

. 明白树和图作为数据结构是如何提供好处的

. 知道何时使用对象或数组同时能作出很好的权衡

. 学习在有大量数据时缓存为何如此重要,同时学习内存缓存和硬盘存储的优劣

. 学习队列和栈的区别

学习这些当然是一件很难的历程,但是为了成为一名全栈开发者,这些付出都是值得的。

路漫漫其修远兮,吾将上下而求索!

原文:https://medium.com/coderbyte/a-guide-to-becoming-a-full-stack-developer-in-2017-5c3c08a1600c

有删改!

使同事羡慕不已的8个npm命令

这篇文章会为你揭示一些有用的 npm 技巧,由于篇幅原因不可能涵盖所有,所以我选择了工程师日常相关且有用的作为本篇文章的关注点。

基本简写

为了大家保持一致,特别是新人,首先我们来快速浏览一些基础的简写。

Installing a package:

通常:

npm install pkg

简写:

npm i pkg

Installing a package globally:

通常:

npm i --global pkg

简写:

npm i -g pkg

Installing a package and save it as a dependency:

通常:

npm i --save pkg

简写:

npm i -S pkg

Installing a package and save it as a devDependency:

通常:

npm i --save-dev pkg

简写:

npm i -D pkg

更多的简写请看官网:https://docs.npmjs.com/misc/config#shorthands-and-other-cli-niceties

接下来让我们开启有趣之旅:

1.Initializing a new package

我们都知道 npm init ,是当我们初始化一个package的第一件事。

npm init

但是,这些问题很烦人,所以为什么不避免它呢?

使用

npm init -y

npm init -f

来解救!

3.gif

2.Running tests

另一个我们都会用的命令是

test```,我们中的大多数人会每天使用,甚至一天几次。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

![4.gif](http://upload-images.jianshu.io/upload_images/76372-0192f44f0c683478.gif?imageMogr2/auto-orient/strip)

幸运的是,使用 ```npm t```,可以做相同的事!

![5.gif](http://upload-images.jianshu.io/upload_images/76372-f1ab73c98f70840d.gif?imageMogr2/auto-orient/strip)


3.List available scripts
--
当我们接手一个新项目时,会考虑如何开始手头的工作。我们经常会自问:我们如何运行项目?有哪些脚本命令可以使用?

一种方法是找到package.json文件然后查看里面的 ```scripts``` 部分。

![6.gif](http://upload-images.jianshu.io/upload_images/76372-7501b8f4fdb3074e.gif?imageMogr2/auto-orient/strip)

当然我们可以做的更优雅一些,可以简单的运行 ```npm run``` 来列出所有可使用的脚本命令。

![7.gif](http://upload-images.jianshu.io/upload_images/76372-4f4b37708b6dfbbd.gif?imageMogr2/auto-orient/strip)

另外还可以安装 ```ntl```(```npm i -g ntl```),然后在项目文件夹下运行 ```ntl```,同时还支持运行脚本。

![8.gif](http://upload-images.jianshu.io/upload_images/76372-c6a12e2e0318c72a.gif?imageMogr2/auto-orient/strip)

4.List installed packages
--

就像上面一样,有时候我们还会自问项目中都有哪些依赖。

我们同样可以打开package.json文件然后查看,但是我们已经知道我们可以做的更好。

使用 ```npm ls --depth 0

9.gif

列出全局安装的包,我们可以使用同样的

的标识, ```npm ls -g --depth 0```。
1
2
3
4
5
6
7
8
9
10
11

![11.gif](http://upload-images.jianshu.io/upload_images/76372-41bd72b97a934e2b.gif?imageMogr2/auto-orient/strip)

5.Running locally-installed executables
--

在项目中我们安装了一个附带可执行文件的包,但是只有当我们通过 npm script 运行是才可用,你或许会惊奇为何?或知道如何避免它?

首先,我们来理解一下为何--当我们在控制台运行命令时,实际上是在系统环境变量的 ```PATH``` 下列出的所有paths中,寻找同名的可执行文件。这就是为何在任何地方都可执行的原因。本地安装的包是把它们的可执行命令注册在本地的,所以它们没有被列在 ```PATH``` 中,同时也不会被找到。

你或许会问:为何在通过 npm script 就可执行?好问题!当以这种方式运行时,npm 做了一些小技巧就是在我们的 ```PATH``` 中增加了额外的目录

/node_modules/.bin。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

你可通过运行 ```npm run env | grep "$PATH" ```来查看,你同样可运行 ```npm run env```来查看所有环境变量,npm 增加了一些有趣的东西在里面。

我们在项目目录下运行 ```./node_modules/.bin/mocha``` 来实际看看效果

![10.gif](http://upload-images.jianshu.io/upload_images/76372-0dc46e037edcfd18.gif?imageMogr2/auto-orient/strip)

是不是很简单?无论何时你想运行本地安装的可执行文件,只要简单的敲入 ```./node_modules/.bin/<command>```。

6.Find your package on the internet
--
你或许会在package.json中发现仓库的地址,同时想问此安装包有什么功能?
简单的运行 ```npm repo``` 就会在浏览器中打开该仓库地址。
同样运行 ```npm home``` 命令就会打开 ```homepage```的入口。
如果你想在 npmjs.com 中打开包的页面,有一个贴心的命令: ```npm docs

7.Run scripts before and after other scripts

你可能对类似 pretest 的脚本属性,它可以帮你在运行 test 脚本之前定义一些代码。
真正会使你惊奇的是,你同样可以在自定义脚本中使用!

12.gif

当你把 npm 作为你的构建工具或者有许多脚本要执行时,这种功能就会很有用。

8.Bumping package’s version

你有一个包,同时使用 semver 做为你的版本记录标准,在你发布新包之前需要填写新的版本号。
其中一种方法就是你打开 package.json 文件然后改变里面的值,但是我们可以不需要这样做。
另一个简单的方法是运行 npm version 并附带上 majorminor 或者 path

13.gif

我希望你从本博文中学到一些东西,并能运用到你的日常工作中。

微信更新了这些内容,你还不知道?

微信昨天更新了一个版本,功能如下:

  1. 可在微信实验室体验正在探索的功能
  2. 聊天中查找聊天内容时,可以查找文件、图片、链接
  3. 群主可在群成员信息页中,了解对方是如何加入群聊的
  4. 选择图片时,可便捷地调整并预览已选择的内容

从上面列出的点,对普通用户 1 和 4 还是值得关注的。

开启实验室功能

按照如下顺序开启:

css-hover
css-hover
css-hover

搜一搜

其中的搜索功能本来就有,这次把它换到了一个更明显的地方。表面看着是换了一个地方,在我体验之后搜索结果还是不同的,从发现页面进入搜索可以搜出小程序:

css-hover

不过从下面图也可以进入,聊天页面的搜索可以看成是一个简化版的搜索:

css-hover

搜索功能不仅仅搜索微信下产生的内容,还可以搜索别的平台下的,甚至说可以是全网(微信搞事情,百度吓尿了么?)。

看一看

大概看了下里面的内容,应该都是公众号(关注或未关注)里产生的东西。现在不知道里面的推送逻辑,应该是依据好友和自己关注的公众号来推送的。

发朋友圈可调整图片

新增了发朋友圈可以长按图片来调整顺序,这个功能还是挺实用的。对那些发有顺序规律的图片还是挺好的。同时还可以同步到QQ空间、facebook、twitter,基本可以做到IFTTT(if this then that)的功能。

版本更新为提到的和微调的功能:

文章置顶

以前未看完的文章可以置顶,同时退到聊天界面,这次我体验下来发现做了微调,置顶之后没有退到聊天界面。感觉不大方便了!

共同群聊

在好友界面下有个 更多,点击可以进入可以看到和好友的共同群聊,这又什么用呢?除了给你一声惊叹,哇,他居然也在那个群里,同时还有一个有用的就是可以找回没有保存到通讯录的群聊。

css-hover
css-hover

收付款

收付款的界面也变了,收款、付款、群收款以及面对面红包被整合到同一个页面中。

css-hover

借图一张

css-hover

颤抖吧!

以上就是我的使用体验和总结。

微信小程序开发小结

我做的一个小程序《看图识字》在4月27日上线。在线上运行也十来天了,这里做个小结。总结一下为何要做这个、做这个遇到的一些问题以及做一个产品(姑且算一个产品吧)的感悟。

为何要做这个小程序?

  1. 主要是因为小孩即将出生,给他做个小东西做个纪念,同时亲戚朋友也有需要的,所以为了解决用户的需求,就产生了做个小程序的想法。可是这个产品的定位还是很尴尬,因为这个是手机上的程序,不太建议幼儿玩。等到快上小学的时候,认认字还是挺好的,可还是得注意时长。

  2. 同时也是为了练练手。

这个小程序的雏形也是参考了一些别的产品,这个东西没什么复杂的东西,基本都是我YY的。主要是我看着开心就行,毕竟我是产品(哈哈),但在新的版本里也加了意见反馈功能希望得到用户的反馈。

遇到的一些问题

####内容:

任何一个产品(网站、APP,小程序,桌面应用等)一定是有内容填充的,而内容的来源是第一个要解决的问题。

根据内容来源的不同,产品的形态又分为如下三种UGC、OGC、PGC:

css-hover

  • UGC:User-generated Content,用户生产内容
  • PGC:Professionally-generated Content,专业生产内容
  • OGC:Occupationally-generated Content,职业生产内容

从定义来看《看图识字》这个小程序属于PGC,出于个人”爱好”,义务的贡献。

我解决内容问题用了一个想法两种途径:

  • 想法:自己找人画或者自己学sketch画 ❌

如果要是按照这个想法做不管是找设计老司机还是我自己搞,估计这个小程序还没上线。如果一个东西拖的太久,慢慢的就失去了做下去的动力,所以我就放弃这个路子。

  • 另辟蹊径,既然不能重头开始画,那肯定得找现成的,所以我就找网上的图片,图片得是一个系列的也就是画风得一致,别一张一个样,然后就找到一个提供免费文档的地方。里面确实有许多图片,找到一个水果系列的一共25张,我就开始一张一张的右键查看地址下载,等我下载几张后,发现很机械。最后临时找了一个python爬虫教程写了一个简易的爬虫下载完了图片。

估计手动下载最多5分钟,可是写爬虫用了半小时😭😭😭。

  • 爬了两个系列之后,就匆匆上线了。用了一两天,发现图片是在是太渣,然后我就到万能的淘宝去寻觅,最后在和卖家的讨论(撕逼)下,把电子版的图片发我了(有可能侵权)。然后就更新了一版加入了新的系列,图片的质量好点了。不在是土八路(GCD万岁),而是国军穿戴整体。

###语音

第二版本加的语音功能,当时我的想法是搜一下网上有没有现成的API直接调用一下,可是没搜到。最后想到的是百度翻译

css-hover

可是等我把:

https://sp0.baidu.com/-rM1hT4a2gU2pMbgoY3K/gettts?lan=uk&text=hello&spd=2&source=alading

复制到浏览器里时,居然把mp3下载下来了:

css-hover

可这并不是我想要的,我想的是直接发音。最后搜到一篇文章:http://dwz.cn/5Xia0K 里面有价值的就是一个地址:

http://tts.baidu.com/text2audio?lan=en&pid=101&ie=UTF-8&text=hello&spd=2

把上面地址复制到浏览器后出现了我想要的:

css-hover

就在我写的时候又发现有道翻译也有一个不错的发音API,自己去找吧!

感悟

从开始有想法到写好第一版本共用2天,因为功能简单同时也是为了先有个大概的东西就匆匆的上线了。如果当时没有那么快上线,若一开始就考虑很多东西,估计已经废掉了。如果快、糙、猛的先上一版,不巧还有用户在用就会不断督促自己修改、优化。

现在也每天看看数据,虽然也有些数据看不懂:

在被”知晓程序”公众号一周最新《晓榜》16期推送后访问达到顶峰,然后就一直下滑 😭 幸福来得突然也不是一件好事。

css-hover

欣慰的是累计用户目前一直是增加的目前总人数是:1150

css-hover

还有一个数据挺好,有29.6%的访问来自于搜索,说明起的名字还是可以的同时需求也是存在的:

css-hover

小程序:

css-hover

你的人生需要一场马拉松

定目标

过年的时候,在家就定了几个小目标,其中一个就是:跑一个半程马拉松。当时老婆听了就说了一句话:“千万别跑挂了!”。

个人认为目标的特点:

短期、具体、具有挑战而又可完成。

短期很好理解不要把战线拉得太长,国家还五年一个大计划呢,所以在时间上拖的太长,容易失去控制。同时自己的付出不能得到及时的反馈,容易疲惫。

具体就是你要干什么

有挑战而又可完成可理解为目标不要太高,也不要太低。比如高中毕业的不要再研究1+1等于几,同样也不要说高中毕业我开始研究狭义相对论。倒是可以研究一下到大学怎么泡妹子(😆😆)

综上所述:

跑2017年4月23日的半程马拉松

是一个符合上述特征的目标。

跑步的动力:

1. 给即将出生(现在已经出生)的小孩一个奖牌,并告诉他:人生即将开始,人生有开心,有痛苦,而你需要的是坚持。
2. 挑战自己,同时锻炼一个健康的身体

准备

经过9次稍微长点的锻炼:

在开跑前我都没有完成一次20公里的距离,所以去跑半马心里是没有底的。在报名后,等待抽签时,结果如下:

没有抽中!!!但是经老司机带路说可以蹭跑,而且还可以弄个假的号码:

城市套路太深,乡间小路太滑!

开跑

4月23日早7点东方明珠附件开跑,本以为5点起来过去很早,谁知:

到的时候已经人山人海,红旗飘展,锣鼓喧天!开跑前最后奏国歌,貌似大家都不由自主的开始唱了,在那种氛围下还是挺激动的,激动的差点少先队礼!😂

随着一声枪响,撒丫子跑!!!

在到第一个补给站时,我已经渴的不行了。真的意识到水的可贵!!!

知乎上有个问题:马拉松运动员比赛时都在想什么? 截取几个:

发枪前——能不能快些呀….挤死了…哥们儿你气球打着我了….站着好累啊!…哎哟有灰机!…“嘿~兄弟状态不错呀”….巴拉巴拉….

嗯~边上那个妹子不错,看起来是第一次跑…要不要搭讪…要不要搭讪…要不要搭讪…卧槽!起跑了!

前5km——啊,好high啊!…啊,人好多啊!…啊!give me five!…草草草!配速高了!憋冲动!

而我:

下一个补给站怎么还不到,渴啊!

10km了,累的不行了,开溜吧!啊,要是这样开溜,丢人啊!开始在坚持一下吧。

这种想法就持续到最后,所以能坚持下来除了毅力,还有不能那么丢人的开溜想法。

还有150m左右时,看计时器2小时28分钟,啊,加速加速,跑进2小时30分钟!耶,过终点!赶紧拍照!

感悟

半马在认真做过锻炼后,还是能完成的。

慢慢的让身体适应节奏,3km、5km、10km、15km、20km,每一级别都跑2-3次,然后进入下个级别。不要图急于求成,急不得,身体会受不了!

跑步时,配速要稳。切记急跑急停,毕竟马拉松不是一个需要爆发力的项目,需要的是耐力!

马拉松是一次与自己的较量与自己的对话,无关他人,战胜自己,就是胜利!

现在在家陪老婆和孩子,感觉自己还没长大,孩子已经出世!从此多了一个称谓,多了一份责任!

Canvas-绘制线

坐标系统简析

左边是笛卡尔坐标系,右边是canvas坐标系。

笛卡尔坐标系(Cartesian coordinate system):

也称直角坐标系,是一种正交坐标系。二维的直角坐标系是由两条相互垂直、0点重合的数轴组成。

canvas坐标系和web坐标系一致,左上角为原点。

绘制线

代码基础:

var canvas = document.getElementById('j-canvas');

if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    // 在此添加代码
}

主要方法:

lineTo()

单纯只用上面一个方法是不能画出线的,需要别的方法配合:

ctx.moveTo(0,10); // 画笔的起点或重新定位画笔

ctx.lineTo(200,10);

ctx.stroke(); // 描边 

绘制结果,如下:

修饰方法:

lineWidth:默认值 1.0

ctx.lineWidth = number;

lineCap: 线的尾部何种样子

ctx.lineCap = "butt"; // 默认值
ctx.lineCap = "round";
ctx.lineCap = "square";

如下:

square的尺寸为: lineWidth/2 * lineWidth

lineJoin: 线与线之间如何衔接

ctx.lineJoin = "bevel";
ctx.lineJoin = "round";
ctx.lineJoin = "miter"; // 默认值

注:round的半径是lineWidth,miter为两条线延伸然后组成一个菱形。

miterLimit:

ctx.miterLimit = value; // 默认值 10.0,(设置为:0, 负值, Infinity and NaN 则忽略)

设置或返回最大斜接长度,斜接长度指的是在两条线交汇处内角和外角之间的距离:

注:只有当 lineJoin 属性为 “miter” 时,miterLimit 才有效。

如果斜接长度超过 miterLimit 的值,边角会以 lineJoin 的 “bevel” 类型来显示(图解 3):

setLineDash():

ctx.setLineDash(segments); // segments 为数组

若数组为:[5,10],设置偶数个数值,[线,空白]交替绘制

线就是5,空白就是10。

如果数组为:[5,10,15],设置奇数个数值,内部会变成 [5,10,15,5,10,15],[线,空白,线,空白,线,空白]

getLineDash():

ctx.getLineDash(); 

返回一个偶数个数字的数组,若设置的为[5,10],返回则为[5,10];若设置的为[5,10,15],返回则为[5,10,15,5,10,15]。

lineDashOffset:

ctx.lineDashOffset = value;

默认值:0.0,设置线的偏移量,可正(整体逆时针移动),可负(整体顺时针移动)

绘制(Marching ants)

var offset = 0;

(function march(){
    ctx.clearRect(0,0,canvas.width,canvas.height); 
    ctx.setLineDash([5, 10]);

    ctx.beginPath();

    ctx.lineDashOffset = -offset;

    ctx.moveTo(10, 40);
    ctx.lineTo(200, 40);
    ctx.lineTo(200,100);
    ctx.lineTo(10,100);
    ctx.lineTo(10,40)

    ctx.stroke();

    // 增加
    offset++;

    setTimeout(xxx,100)
})();

原理:offset每100毫秒增加一个单位,每增加一个单位整体就向右移动一个单位,再配合 clearRect 清除画布,视觉上感觉就是在顺时针移动。