2017年,过去三年回顾总结

2016年的年末 [ 12.24] ,我在美团外卖满了三周年的时间。回过头来看看自己,这几年的变化确实还不小。看着往年留下的寥寥数笔,决定今年还是写些什么把。就当是这几年的一个总结。

迷茫

如果把毕业后的生活,按照五年一个阶段的划分。对于这部分应该是第一个五年计划中的阶段。初出茅庐,一直处于比较焦虑的状态。隐隐的有种声音经常在我的内心盘绕“在你最好的事件里,你想去做点啥有价值的事情~ ”
对于这个问题,其实我也不知道该怎么回答。
于是乎,开始了寻找答案。我折腾,再折腾的从南京到了北京,到无锡再回南京再回北京。近三年的时间里,换了很多城市,走了很多地方。捣鼓了不少东西。结识了了不少各式各样的人。

不过值得一提的是蹉跎的时间中,不经意间练就了一手吉他的技巧,哈哈哈。鼓吹到码农中吉他玩的最好的,玩吉他的人中代码敲的最溜的( 虽然后来发现,天外有天,人外有人啊 !)。

缘起

来到美团外卖是个偶然的机会。
当年的美团,在团购大战中异军突起。团购的这种模式,却是一直饱受质疑的。
13年巧合的机缘下,来美团面试:
一面是前端的技术面,聊了很多基础方面的题目,聊得应该还行。
二面是我后来的老板,看着是个瘦瘦小小,其貌不扬的人。但是却非常的精神,谈吐之间中气十足。
面试完了我就回去了。美团的面试我也没放在心上,直到后边美团的HR联系了我。说三面不需要了(一脸黑线)。知道我算是通过了可以到了谈 OFFER 的阶段了。
手头当时就有了几份 OFFER。选择美团只是感觉美团 OFFER 略高的同时,跟HR聊天起来比较直接。不想某司的 HR,为了 500块钱,墨迹上好几天。甚至威胁我,也必须卡在这儿的。哈哈哈。我也是很无语。

在未来老板一通一通电话的 “慰问下”,于是13年底加入了美团的一个内部创业小项目“美团外卖”。当时的团队包括我只有6个RD。三个后端RD,一个iOS,一个安卓。我作为了项目组第一个前端工程师加入了美团外卖。

当年的我,对“创业”,做从0到1的事情。其实并没有太多的概念。大部分的程度上,我能理解的了的,都是父母那代人,或者老师们。给我们灌输的找个好工作,好好干活的思想。
后来,我才逐步的意识到。我遇到了的这一群是多么牛逼和有想法的人,也接触过的很多事。某种意义上讲,美团外卖的这段工作经历,才算是我工作生涯中的第一个职业导师。

成长

a). 关于技术
在外卖的三年多时间里。见识学习了很多牛人的做事和工作的方式。
从零开始搭建了美团外卖的前端基础设施,应用在了大部分外卖的业务系统中。参与过外卖早期基本上所有的业务线。前两年多的时间里,一直在写代码,技术上有着不小的长进。在这个过程中,也逐步的拉扯起了一只20多人的团队。

前端圈子中关于技术的撕逼比较厉害。隔三差五的会在微博上发起一波。

具体技术的优劣,我就不做评判了。但是我的观点始终如一,“存在即合理”。至于有的框架的流行,有的框架的默默无闻。很大程度上其实取决于们暴露的 API 设计的是否符合了大众开发者的口味而已。所以,其实我一直认为,一个好的工程师,某种意义上,也会是一个不错的产品经理。
流行框架的作者,一方面,是他们有着一定的技术功底,其次,他们也有着能被大部分接受的技术理念理念,在他们的框架中得以落实。例如 jQuery 的 “select and do”,这个简单直接的理念最容易被大部分人接受的。早期 Moontools 比较推崇的 “一切皆是对象”,就没有这么好的运气,慢慢的会被淹没。

自己的框架能够被大部分人使用,对其作者也会有不断地敦促的作用。进而进行持续的迭代,迭代过程中会变得越来越完善。
有的时候是一些业务场景来倒逼了技术的提升,之前 @玉伯也叫黑侠 在文章中也提到过。眼瞅着 npm 的作者 isaacs,从 npm 项目之初,这个小伙的代码质量,从稀松平常到不断的老练。

b). 关于业务
在大部分的场景中,技术是服务于业务的。脱离了业务技术的独立存在毫无意义。脱离了技术的驱动,业务进展的也未必会顺风顺水。把持好两者的平衡,不是一件简单的事情,尤其是在一个高速发展,存在于了生死边缘的业务而言。对于一个技术管理者,会有不小的压力。
很多时候技术的选型,考虑到的最主要因素,并不是这个技术的优劣。例如,举个栗子:一个月内,某团队能扩招10个java工程师,而相同工程能力的node.js工程师,只能找到1个,甚至找不到。那站在最终业务的角度,该如何决策应该是一目了然的。

美团外卖刚开始所属的部门叫做新产品部,在团购的格局趋于稳定的情况下。作为一个新尝试性项目在内部发起。
几个RD同学在码砖之余,甚至会去帮助销售发发传单、搞搞地推。经常的大清早,就能够听见一群人在会议室响亮有节奏的喊口号。当时我们也都开玩笑道,我司是不是有传销的业务~ ?
美团外卖的业务,从我刚加入的时候每天十来单,短短的三年事件里就,到峰值时候的 900 多万单/天。这样的业务场景不多,能够见证了这个过程,陪同这么多牛人一起走过中间的路。回头想想,实在是不容易,却也是幸运至极。
中间有一起开心过,也有一起互怼过。时过境迁,都算是一种财富的沉淀吧。

c). 关于招聘
我的前端团队,从最初的一个人,到目前的24人。粗略的算下来,面试了约 400多 名候选人。
招聘的过程,对面试官技术水平的提升也算是一种不断的鞭策。很多的面试官,都不是太合格。包括我们自己的面试官,往往会陷入一种,以己之长,考别人之短的陷阱,然后基于此得出一个结论。要知道,很多候选人来面试是经过精心的准备的。这体现了候选人对待面试的重视,本无可厚非。但是给面试官出了个难题,撇开“己长”,又如何去考察候选人呢?

衡量一个优秀的候选人,我跟 @左耳朵耗子 老师的观点大概的一致。
高效的学习能力解决问题的能力。专业能力,固然非常的重要,但是在大部分的职位需求中,这两点相比较,会显得不那么重要的。当然,我坚信拥有这两种能力的人,通常情况下,专业能力也不会差。
闻道有先后,术业有专攻。在前端知识体系的这个大杂烩之下,知识点纷杂又繁多。极少极少的人,能够做到多面手。有着较大的概率遇到的一个优秀的候选人,跟自己的知识体系不在一条路子上。

衡量解决问题的能力这块。我个人而言,有两种方式,一种是做问题的情景假设。一种是手写代码。问题的情景假设这个很好理解,对于我扔出来的一个问题,候选人接触到过最好。就算没有接触过,也没关系。
聊聊解决的思路是否足够鲁棒,足够细腻,边界情况是否考虑得到,是否可以根据已有的知识沉淀触类旁通,举一反三。这个过程会显得尤为的重要,甚至比直接告诉我答案来的重要。
手写代码,是个非常好的方式考察候选人的方式。不经意间,可以透露出一个人做事的态度是否踏实亦或是浮躁。完成的好坏与否,对这个人的逻辑思维能力、代码熟练度也是个非常好的体现。通过手写代码,也能够反衬出情景假设中的的一些结论。

高效的学习能力。这个则需要从候选人过往的经历中评断出来,例如:能够熟练上手的技术栈、学习的渠道,意愿、或者是否有自己的学习方法论。外卖之前有位面试官,有种有意思的考察学习能力的思路。他跟你介绍下一门新语言的特性,再让你用新语言去迅速的描述一段逻辑。
招聘这块,有个对面试官较大考验的,是否有足够的胸怀和对自己的情绪的控制能力。一个团队,一个业务的长足发展,需要大量的人才。而往往的牛人,是有着自己比较独特的脾气、秉性的。这样的人在加入团队以后,会给团队带来新鲜血液的同时,也会带来一些较大的不确定性。这对候选人,甚至管理者的权威是个挑战,所以有时候需要一定的胸怀来包容着一切。
如果面试官自己没管控好自己的情绪,可能会出现看这个候选人不爽,无法理性冷静的分析情况。会和候选人互怼到底,从而错过了一些真正的优秀人才。

综上,这也就是我们常说的,一流的人找一流的人,二流的人找三流的人。

d). 关于团队
一个团队需要多种不同的角色,才能运作的更好。有的人把这几种角色称之为:将才,帅才,兵才。也有的人把它称之为唐僧,猪八戒,孙悟空。
各种说法,我都有耳闻。但是我想,本质上是想通的。一个独立的团队,需要有人坐镇指挥大旗的方向,团队的价值观,团队的愿景,团队的文化,团队的氛围等等。这一切是跟这个团队LEADER的个人的性格息息相关的。
如果团队足够大。再细分下午需要有人带领小团队高效的执行拆解出来的任务的,任务完成的50%和120%的漂亮,全部依赖于这个小团队的负责人的决策。
也需要高效的执行者。
一个团队良好的氛围,也需要团队的成员不断的带动起来。

对于管理,没有一个标准的答案该怎么样做才好。如果非要追求一个终极的结论怎么才能做到最好的话,我觉得应该对“人性”的理解,和把自己的玻璃心慢慢砸碎的这个过程吧。

e). 做有价值的事情
相比于刚毕业时候的混沌。对于过去的几年,我该去做什么样的有价值的事情,这个问题的答案也在我心中变得不断明晰起来。这个过程,花了我很多时间去不断地思考和试错。
作为一名工程师,一名管理者。是需要去解决一些实际存在的问题,让各种的 bad case 得到更好的解决。
去选择性的做一些真正有价值的事情,才是一个工程师的价值所在。
什么是“有价值”并非那么容易的判别。往往需要有着长时间的阅历、积淀、沉淀、才能够妥善的给予现状的分析并作出规划的。
眼界、思路、想法比技术来的重要,这是我在这几年里体会比较深刻的一点。技术水平可以进行闭关修炼,短期进行内强化,而有些东西是无法一蹴而就的。

未来

一路走来,从一个愣头青。到目前负责20多人的大型业务的前端团队的怪蜀黍。一路不容易,需要一一的感谢很多人给予的机会和指导。

对未来的期许,始终不灭。
五年记为一个成长,毕业七年。练就了一手的技能,继续做一些更有意思的事情吧。

树莓派(MCU)中python读取jy901陀螺仪数据

前段时间折腾四轴飞行器。 飞控这块打算用陀螺仪和树莓派的方式来实现。不要问哥为啥不直接买现成的,因为我们是有 ( mei ) 逼 ( you ) 格 ( qian ) 的工程师。

后来我发现原来一个飞控大概是我买的陀螺仪和树莓派的成本的1/5吧 --! 摔啊 !!!
某宝上搜索结果比较多的是国外产的10块钱都不到的大众陀螺仪~ jy901貌似是款国产的陀螺仪芯片。
本着“便宜没好货”的思想作祟下。再加上jy901 PR文稿的的忽悠,就果断的下单了。

模块的示例中,大多都是C代码。对于使用者而言比较晦涩难懂。 Python 的简易示例代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*

#
# @author XU Kai(xukai.ken@gmail.com)
# @date 2017-01-21 星期日
#
#
# #fileOverview 树莓派串口操作事件,用来输入和输出陀螺仪数据信息 
#
#
#

from __future__ import division

import os
import sys
import math
import codecs

import serial

sensor = serial.Serial(port='/dev/ttyAMA0', baudrate='9600', timeout=1)


def convert(hexVal):
    return int(codecs.encode(hexVal, 'hex'), 16)


while True:
    data = sensor.read(size=1)
    if (data == b'\x55'):
        print('Get the data !')
        sensor.read(size=10)
        break

    print('trying', data)

try:
    while True:
        data = sensor.read(size=11)
        if not len(data) == 11:
            print('Byte error !')
            break

        if data[1] == b'\x50':

            # print(convert(data[7]))
            pass

        # Angle Output.
        if (data[1] == b'\x53'):
            hexVal = []
            for i in range(11):
                hexVal.append(convert(data[i]))

            ax = ((hexVal[3] << 8) | (hexVal[2] & 0xff)) / 32768 * 180
            ay = ((hexVal[5] << 8) | (hexVal[4] & 0xff)) / 32768 * 180
            az = ((hexVal[7] << 8) | (hexVal[6] & 0xff)) / 32768 * 180

            print(round(ax, 3), round(ay, 3), round(az, 3))

except KeyboardInterrupt:
    sensor.close()
    print('Close the sensor !')

其中有几点需要说明下:

  1. a). 该段示例代码是对串口信息的读取。不包含数据的写入。
  2. b). /dev/ttyAMA0 是树莓派的串口在设备中的名称,依不同的设备而异。

亲测可用,欢迎交流。

Enjoy it !
转载请注明出处
botobe.net
本文Github链接

树莓派智能小车控制

前段时间折腾了一台小车,使用树莓派进行的控制。DEMO和硬件相关的展示部分如下:

软件相关部分为了三块:
一个是小车端(在树莓派中运行)
一个是服务器端,用来中转手机发送给小车的指令。
一个是手机端,用来做小车的遥控器(目前仅包括了小车前后左右和摄像头上下左右的控制)。
三个部分使用socket协议进行连接。相关代码分享在了Github上。
仓库分别是:
小车代码仓库服务器端仓库遥控器代码仓库
其中小车部分的代码仓库中。积累了不少对树莓派的控制相关代码演示(高低电平以及PWM信号)。
欢迎一起交流学习。

Enjoy it !
转载请注明出处
botobe.net
本文Github链接

coffeescript 词法分析

无论是对我们的代码解释执行,还是编译执行,词法分析都是作为第一个环节开始的。
词法分析的过程,可以理解为将字符序列转换为单词(Token)序列的过程。
本文中以如下的coffeescript代码为示例:

# Assignment:
number = 42
opposite = true
# Conditions:
number = -42 if opposite
# Functions:
square = (x) -> x * x

这里的单词(Token)是指一系列最小的对程序来说有意义的单元,例如"number", "=", "(换行)", "(空格)"等等。
对于coffeescript而言,有10中类型的token
1. identifier(标识符):脚本中各种独立的标示符,例如number,opposite等等
2. comment(注释)
3. whitespace(空格)
4. line(换行)
5. heredoc(本地注释):以"""或者'''开头的代码注释
6. string(字符串):匹配的coffeescript中得字符串,例如'test'(coffeescript中得字符串用单引号围起来)
7. number(数字):匹配的数字,包括了8进制数字和16进制的数字
8. regex(正则表达式)
9. js(js):匹配的正则为/^[^\\](?:\.[^\`])*`/,我觉得我的解释太TM多余了,还是看代码来的直观
10. literal(加减乘除,位运算,与或之列的符号)
输入的是如上的一串coffeescript的代码,输出则是按照这是种token分类好的程序的最小单元的一个数组,提供给语法分析器继续进行分析。
例如:


Enjoy it !
转载请注明出处
botobe.net
本文Github链接

coffeescript 编译调试剖析

工欲善其事,必先利器。我们用node-inspector来调试coffeescript的编译。
用全局的方式安装node-inspector

sudo npm install node-inspector -g 

新建一个叫coffee得目录,用来作为我们的工作目录。
在目录中新建一个package.json文件,可将如下内容填入其中(截止目前为止我们用coffeescript最新的1.8版本进行调试)

{
  "name": "coffee-debugger",
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "coffee-script": "1.8.0"
  }
}

再命令行中运行如下命令安装当前工程依赖的coffeescript

sudo npm install 

在我们的工作目录中,新建一个用来测试的coffeescript脚本main.coffee
这个时候工程中的目录结构应该是这样

下边就可以正式的开始进入主题了,打一个命令行,启动node-inspector

node-inspector

再打开一个命令行,并且进入到coffee目录中

node --debug-brk node_modules/coffee-script/bin/coffee -c main.coffee

在浏览器中打开URL 127.0.0.1:8080/debug?port=5858 就可以开始调试coffeescript的编译过程了(-c开关表示将main.coffee编译成为main.js脚本)

Enjoy it !
转载请注明出处
botobe.net
本文Github链接

[美团外卖] 长期诚聘前端,高级前端,前端技术专家

我们是谁?

我们是美团网的前端团队,负责美团外卖业务
我们是有趣的年轻人,待人真诚,做事靠谱,创业团队氛围,简单可依赖

工作职责?

指导初级工程师
持续优化,建设前端基础设施
支持美团外卖各个业务线前端开发需求,为用户呈现最好的界面交互

职位要求?

能独立完成前端开发工作;
了解对各种情形下的前端解决方案;
精通 HTML/CSS/Javascript 等前端技术,能轻松写出符合 W3C 标准、兼容主流浏览器的代码;

本科以上学历,计算机、数学等相关专业毕业(或者计算机基础非常扎实);
熟练的使用一门后台技术( node.js/python/PHP/java ),因为我们觉得,行于前端,而不应止于此;

同时,我们坚信一点,闻道有先后,术业有专攻,上边的都可以无视
我们欣赏的同学,需要有强大的自驱力;积极主动,有想法;并且知道如何不断持续的提升自己;精于问道,勤于实践
对技术有一定的热忱和激情,发自内心的热爱这份职业

我们提供了什么?

一份会令你满意的薪 [ 15k起 ],和能力成正比;优秀的同学会有期权激励
一套程序猿的顶级梦幻装备, Retina 屏幕的 MBP ,一把超舒适的人体工程学座椅,以及 27 寸外接大屏
一群聪明的小伙伴们
一个能够充分发挥你才能的轻松,愉快的工作环境
一家满了极客氛围的公司

所以?

坐标帝都,望京

如果你觉的似乎和我们存在了那么一点儿的相似和联系,就可以过来和我们聊聊吧
不用担心档期的问题,这个职位我们会长期为你留着!
邮件发送简历至: xukai#meituan.com => (# 改为 @)

原地满血复活

当我下定决心开始做一个有趣而有意义的事情时,我都没有想到自己的动力会那么大,被自己都吓到了~ 哈哈 :)

在博客杂草重生的荒废了n个月之后,趁着最近略有闲暇,噌噌噌的花了两个星期的业余时间,把博客重新又搞起来了。
新在Github上开了一个repo,把原先的数据库由mongodb改成了mysql。于是乎还是发现mysql用起来比较顺手啊~ VPS由原先的burstNet升级到了linode,express更新到了最新的版本,作为老本行的前端也做了深层次的优化。
瞬间有种鸟枪换炮,犀利哥走上了巴黎时装周感觉~

当然,博客最重要的还是内容啦。
从2010年6月份开始,到2014年的10月份,将近四年的时间遇到过不少人不少事,有傻逼的,又聪明的,有二逼的,有装逼的,有真诚的,有需要感谢的,有永远不想见的,有开心的,有难过的,有值得骄傲的,有痛苦的 ... ...
博客换过域名,换过内容,换过主题,换过技术架构。
总之贯穿了我毕业后的整个职业历程,也记录下了我的成长。看着自己从一个整天自怨自艾的小青年变成今天的自己。想想还是蛮欣慰的。这些年,没有白白的从指缝间溜走。
大大小小的写了约有四十来篇文章,网站迁移过几回,丢失了不少文章和图片。懒得去翻硬盘里那些百八十年的老数据去找了。以往对数据备份完全没啥概念的我,这回可是深有体会了。纸上得来终觉浅,这就算是成长的学费了吧。

总体看来,技术文章的数量在不断的减少,但是质量越来越高了,多了些体会和感悟。
重新上路,相聚无时,后会有期!

过年啦!

已经是年初五了,假期的日子过得就是这么的迅速啊,总是有昨天才放假的感觉。
回顾过去的2013年,有很多想说的话,留给2014年的结尾吧!

大家新年快乐,大吉大利!

2014.02.04
此文仅以刷一下微不足道的存在感
Merci !

记在2013的双12

又到一年的双12,在历史上那场著名的双12后52年,我也开始了星辰大海的征途。
不记得何时开始,给人们最大的关于12.12的印象莫过于12.12活动了,暂且抽象的理解为给我庆生了吧,哈哈。

对于2013年,遇到了一些人,奇葩也好,特殊也罢,凭借我一凡夫俗子的理解能力是真心无法理解他们的境界。我无法想象,这人是怎么做到,刚刚是还是一个表情,扭头过后又是另外 一种心态的。一切来得太过突然,着实让我吃了一惊。

认真对待我做的事情,真诚对待身边的每个人,扪心自问,我问心无愧!

n年后再回头看看这些事情,对于生活来讲也算是一种历练吧,过了就过去了。
希望上诉的言论不会让人为这是在抱怨,如果非要下个定义,我认为应该是写实。我不会去抱怨什么,因为最起码没人欠我钱,也没什么可以抱怨的了。
还能每天享受着灿烂的阳光,拥有者想走就走的自由,服雾这大帝都的空气的时候还有活蹦乱跳的拥有个健健康康的我,哈哈。
最重要的,在我困难,迷惑,郁闷,压抑的时候,爸爸妈妈还有媳妇儿会始终会站在我身边继续给我动力和支持。
关于我的生日,也谢谢你们每年总是第一时间送来祝福。

139邮箱,招商银行也会发来祝福短信。因为我知道,这些都是脚本,程序自动完成的。他们背后站着的都是一台台冷冰冰的机器。如果我从未用过他们的服务,也会接到这样的祝福吗?本质上就是不纯粹的。
就好比逢年过节的大伙们群发短信一样,好歹你也加上个祝福对象的名字哉!!再加上一句真心的问候,手指挪挪的功夫,否则意义在哪里?!
把一毛钱省着留给路边的乞丐吧,还能到他一句谢谢。要不就去买纸巾上厕所的时候擦屁股也比这样来的实在。

感谢那些给我梦想,给我机会的人。能回报你们的就是我的汗水和心底的一声谢谢。
也谢谢那些把我的梦想和计划推向边缘的人,让我认清了原来我们貌似平静的生活不是一个乌托邦。
骚年,一切才刚刚开始,我们的征途星辰大海!

本文Github链接

自定义你的javascript事件

浏览器内置了一些javascript的方法,比如说click, mouseover, mousein ... 可以在用户进行了一些浏览器内置的默认行为(点击,鼠标滑过DOM)的时候会触发。
说道自定义javascript事件,给大家印象比较深的也许是jQuery的bind方法,可以添加一些用户自定义的事件,再用trigger的方法来触发之。
基本的实现代码如下:

/**
 * 事件管理组件
 * 版权所有(C) 2013 EchoFUN (xukai.ken@gmail.com)
 * 
 * 2013.12.12 初始化文件。
 * 
 * Example:
 *   var test = document.getElementById('test');
 *   evt(test).bind('custom', function() {
 *
 *   })
 *
 *   evt(test).trigger('custom');
 *
 */

;var cacheId = 'cache' + setTimeout(function() {}, 0);

var evt = (function(global, cacheId) {
  'use strict';
  var isIE = !!document.attachEvent;
  var typeExpress = /^[a-z]+$/i;

  // 缓存所有的事件。
  var events = {};

  // 产生一个唯一的键值。
  var globalId = 1;

  function wrap(node) {
    return new _wrap(node);
  }

  function _wrap(node) {
    var _node = (node && node.nodeType == 1) ? node : '';
    if (!_node) {
      return 'Invalidate node !';
    }

    _node[cacheId] || (_node[cacheId] = globalId++);
    this._node = _node;
  }

  function _type(o) {
    var type = {}.toString.call(o);
    return type.slice(8, -1).toLowerCase();
  }

  var proto = _wrap.prototype;
  proto.bind = function(type, handle, capture) {
    if (_type(type) !== 'string' 
      || !typeExpress.test(type) 
      || _type(handle) !== 'function') {
      return 'Invalidate params !';
    }

    var node = this._node;
    if (isIE) {
      node.attachEvent('on' + type, handle);
    } else {
      node.addEventListener(type, handle, capture);
    }

    // 如果还未开始对这个对象有缓存,则加入缓存序列。
    if (!events[node[cacheId]]) {
      events[node[cacheId]] = {};
    }
    var evts = events[node[cacheId]];
    if (evts && evts[type]) {
      evts[type].push(handle);
    } else {
      evts[type] = [handle];
    }
    return this;
  };

  proto.unbind = function(type, handle, capture) {
    if (_type(type) !== 'string' 
      || !typeExpress.test(type) 
      || (handle && (_type(handle) !== 'function'))) {
      return 'Invalidate params !';
    }
    var node = this._node;
    var evts = events[node[cacheId]];
    if (!evts[type]) {
      return 'Not exist specified event !';
    }

    if (isIE) {
      node.detachEvent('on' + type, handle);
    } else {
      node.removeEventListener(type, handle, capture || false);
    }
    if (handle) {
      for (var i = 0; i < evts[type].length; i++) {
        if (evts[type][i] == handle) {
          evts[type].splice(i, 1);
        }
      }
    } else {
      evts[type] = [];
    }
    return this;
  };

  proto.trigger = function(type) {
    if (_type(type) !== 'string') {
      return 'Invalidate params !';
    }

    var args = Array.prototype.slice.call(arguments);
    args.shift();
    var evts = events[this._node[cacheId]];
    if (evts[type]) {
      var evtsList = evts[type];
      for (var i in evtsList) {
        evtsList[i].apply(this._node, args);
      }
    }
    return this;
  };

  return wrap;
})(this, cacheId);

完整示例请移步Github event.js文件

对javascript的事件自定义,只是其庞大事件系统的冰山一角。
口水横飞的讲了这么多,不知道你会不会有这样的疑问。
自定的这些事件有个蛋用啊!?

网上关于自定义事件的方法一抓能有一把,但是总结为何这样做的文章却很少。
具我在项目中使用情况看来,可以总结出起码有如下两种情形:
a). 在制作一些前端组件的时候,可以为特定的事件添加钩子
举个栗子:
人人网的表情组件(PS. 居然注释部分没有压缩掉哈,剩下了我的口水了。)
开发人员可以对new了XN.ui.emoticons这么个对象后的返回值添加各种事件。组件中已经在各个关键节点(渲染结构,绑定事件,展示)的地方fireEvent了这些事件。
这样就可以进行无侵入式的编程。在不改变原有逻辑的情况下,添加一些自己想要的行为,岂不爽哉!?

b). 模块化开发中,可以方面的为各个模块之间进行解耦
现在的前端工程里,有追求的前端们(咳咳,你懂的!)大多使用了common.js的规范来组织前端代码,各个模块的数据和操作都可能是独立的,但是模块和模块之间的沟通通过什么方式来进行呢?
(自定义事件!)
恭喜,都会抢答了。
细细说来,有点类似于前些文章中聊到的观察者模式,在我发布了一篇微博的时候,需要出发右侧的微博数目。这个时候,我就可以在发布框的模块中,trigger或者是fireEvent一下事先已经绑定在右侧数目计数器上的一个自定义的事件,这个举例比较简单,如果模块功能很复杂,就能做到充分的解耦。
能力有限,欢迎各路大神继续补充和拍砖。

写在结尾处:
之前的文章里很少有提及CSS的部分,之所以不涉及这块,并非不是很了解。奈何没有像@张鑫旭单口相声般的牛逼技能,写出来的文章就像懒婆娘的裹脚布一样。这个也是需要我学习和将强的地方啦,哈哈。

Enjoy it !
转载请注明出处
botobe.net
本文Github链接

2013.12.13
最近情绪不佳,有点小郁闷!
依旧Merci !

下一页