jquery整体架构

本文将探索jQuery是如何从最简单的问题开始,并逐步实现羽翼渐丰的演变过程,从jQuery核心技术的还原过程来理解jQuery框架的搭建原理。

原型继承

在JavaScript中,函数无处不在,它可以归置代码段,把相对独立的功能封装在一个函数包中;它可以作为一个对象;它也可以用来实现类。

例如,定义一个最初的jQuery类:

1
2
3
var jQuery = function() {
// ...
};

上面定义了一个类,类名叫jQuery,我们可以把它当做一个函数,函数名为jQuery,当然,我们也可以把它当做一个对象,对象名就叫jQuery,在JavaScript,一切都是对象。

上面定义的是jQuery一个空函数,啥都没做,实际上,这个函数就是面向对象语言中所谓的构造函数,是用来创建类的。

JavaScript中就是使用function关键字来定义类的,类最基本的特性就是封装、继承、多态等,JavaScript没有extends、implement等关键字,它是通过原型(prototype)来实现的。

js中的每个函数都具有一个prototype属性(不同于

1
2
3
4
5
6
7
8

现在我们就来扩展jQuery的原型:

```javascript
var jQuery = function() {};
jQuery.prototype = {
// ...
};

如果你觉得jQuery.prototype名称太长,木有关系,你可以为其重新命名,如fn:

1
2
3
jQuery.fn = jQuery.prototype = {
// ...
}

当然,如果你还觉得jQuery名称太长,你也可以给jQuery定义一个别名,比如$:

1
var $ = jQuery = function() {};

接下来我们给jQuery的原型对象添加一个方法size和一个属性jquery:

1
2
3
4
5
6
7
8
var $ = jQuery = function() {};

jQuery.fn = jQuery.prototype = {
jquery: '1.3.2',
size: function() {
return this.length;
}
};

如何调用这些方法和属性呢?

阅读全文

jquery动画实现原理

最近想写个动画库练练手,在写之前,先看了jquery动画方面的源代码,为此写篇博文记录一下心得体会。

概述

jquery动画很强大,它有一个很强大的特性:动画队列,比如:

1
2
3
4
5
6
<button id="animation-test">test</button>
<script>
$('#animation-test').click(function() {
$(this).animate({width: 200}).animate({opacity: 0.5});
});
</script>

示例:运行一下

    
    

可以看到,该按钮的动画按照调用animate的顺序播放了!

阅读全文

批量svn delete

如果我们在某个目录中删除了一些已经在svn版本库中的文件或者目录,但是还没commit,svn status查看一下状态:

1
2
3
4
5
6
7
!   x/xx
! x/xx/x.js
! x/xx/x.css
! x/xx/x.png
? x/xx/x.jpg ## 其他状态的文件
M x/xx/xx.js ## 其他状态的文件
...

现在我们想svn delete一下带”!”状态的文件或者目录,如果被删除的数量不多,我们当然可以挨个svn delete

但是数量很多的情况下,delete起来就麻烦了,不可能挨个delete,这个时候可以利用shell来批量删除:

1
svn status | grep ! | awk '{print $2}' | xargs svn delete

svn status一下,可以看到:

1
2
3
4
5
6
7
D   x/xx
D x/xx/x.js
D x/xx/x.css
D x/xx/x.png
? x/xx/x.jpg
M x/xx/xx.js
...

已经成功delete了,再commit一下就搞定了!

添加已有项目到github

在本机上搞了一个项目,还没添加版本控制,现在想把它添加到github上,怎么办?

我第一个想法就是这么干:在github上新建一个repo,clone到本机,然后把已有项目的代码拷贝过来。

但是显然,这种方法很不方便,其实可以有更好的办法。

1
2
cd my_project
git init

这样就创建了一个local repo,现在就可以把代码添加进去:

1
2
git add .
git commit -m "first commit"

ok,接下来就是创建remote repo了,到github上创建一个新的repo,怎么创建可以参考这里

创建完成后,就可以得到一个远程仓库地址,将该地址添加到local repo中:

1
git remote add origin https://github.com/yourname/my_project.git

更新remote repo到local repo中:

1
git pull origin master

现在,我们就可以把代码添加到github上了:

1
git push origin master

到github上查看一下,代码已经提交上去了,搞定!

前端开发集成方案

在前端开发过程中,我们也许都会遇到这样的场景:

  • 有新项目了?A: 赶紧搭起开发环境; B:去xx项目那边拷一份过来改改吧;
  • 去哪下jquery 1.9.1版本啊?官网找半天没找着;
  • 代码里面写多了个逗号,导致ie报错了?赶紧人肉查一下;
  • 项目要上线了?赶紧想办法合并、压缩、加个版本号;

诸如此类的问题,老在做重复工作,太枯燥了…

come on,别忘了我们是程序员,重复的工作应该交给程序来干!

我们需要一种自动化的前端开发集成方案!

那么,前端开发集成方案应该具备什么功能呢?在我看来,它需要以下技能:

  • 一个脚手架,用来自动生成项目的基础结构、生成一些基础代码等等。
  • 一个build工具,用来执行各项自动化任务,比如语法检查、合并、压缩等
  • 一个包管理器,用来导入一些基础库等

基于以上需求,我找到了一套叫yeoman的解决方案,它包括了三方面:

  • yo:脚手架工具
  • bower:前端资源管理器
  • grunt:任务型build工具

以上三个工具是独立维护的,它们可以很好地工作在一起,组成一套完整的前端开发集成方案。

yo脚手架

yo是一个脚手架工具,安装它:

1
npm install -g yo

yo可以生成多种类型的项目/代码,但这需要依赖于generators,比如我们想生成一个web应用,我们需要先安装一下generator-webapp

阅读全文

gem安装compass问题

最近想玩玩compass,所以就试了一把,按照官网的说明,先安装compass:

1
gem update --system && gem install compass

安装完成后,却发现找不到compass命令(系统是mac os x 10.9)。

这问题应该是gem把compass安装到了一个不在PATH中的目录所导致的,于是就开始了以下排查过程:

1
which ruby

我的是安装在/usr/local/bin/ruby,进到该目录中:

1
ls -l | grep ruby

找到ruby的原始安装目录:

ruby -> ../Cellar/ruby/2.0.0-p195/bin/ruby

进入到以上目录后,发现同目录下有个compass,而这个目录并不在PATH上,于是就出现了:

compass not found

很显然,造成这个问题的原因就是因为:ruby是通过brew安装的,而brew安装ruby的实际目录并不在PATH上。

所以,为了让compass命令可用,我们需要手工建立一个softlink:

1
hushicai: /usr/local/bin $ ln -s ../Cellar/ruby/2.0.0-p195/bin/compass compass

搞定!

web worker简介

Web Worker规范定义了在网络应用中生成背景脚本的API。

我们可以通过Web Worker执行一些操作,例如触发长时间运行的脚本以处理计算密集型任务,同时却不会阻碍 UI或其他脚本处理用户互动。

值得注意的是,规范中提到了两种Worker:专用Worker以及共享Worker。本文只讲专用Worker,下文称之为“Web Worker”或“Worker”。

入门

Web Worker是在独立线程中运行的,因此,它们执行的代码需要保存在一个单独的文件中,我们可以这样创建一个Worker:

1
var worker = new Worker('/assets/js/tests/simple-web-worker.js');

如果指定的异步下载文件存在,浏览器就会生成新的Worker线程。在完全下载并执行文件之前,系统不会生成Worker。如果指定的文件不存在,Worker就不会创建成功。

全局作用域

Worker拥有一个独立于JavaScript执行环境的全局作用域,它不能访问DOM以及大部分BOM,它只能使用JavaScript的一部分功能:

  • XMLHttpRequest
  • self,Worker作用域内的全局对象,等同于Worker中的this
  • navigator,这是个被阉割的对象,在Worker中,它仅包含了部分属性
  • location,等同于window.location,但是所有属性都是只读的。
  • setTimeoutsetInterval
  • 一个importScripts方法,用于向Worker注入外部脚本文件。
  • 所有ECMAScript规范中定义的构造器。

既然是一个独立的执行环境,那Worker中的所有全局变量都应该是self的属性,比如:

1
2
3
onmessage = function(e) {
// ...
}

这样写虽然没问题,但是不好理解,所以建议这么写:

1
2
3
self.onmessage = function(e) {
// ...
}

其实,更优雅的方式应该是这样:

1
2
3
self.addEventListener('message', function(e) {
// ...
}, false);

消息传递

Worker不能直接影响页面,它需要通过一个消息系统来传递消息。

Worker可以通过postMessage方法来传递消息,例如:

阅读全文

mac os x开机启动goagent

怎么在mac os x上让goagent开机自启动呢?

其实很简单,在goagent打包的文件中就有一个叫addto-startup.py的文件。

我在目录goagent/local下找到了它,那么就需要执行以下命令就可以开机自启动了:

1
2
sudo python addto-startup.py
sudo launchctl load /System/Library/LaunchDaemons/org.goagent.macos.plist

一切ok!

vml元素设置css opacity样式导致的图像锯齿问题

使用vml创建图形时,因为图形下还有一张底图,所以需要将vml创建的图形设置一定的透明度,以便可以看见下面的底图。

开始时,使用了ie的滤镜透明filter:alpha(opacity=xxx)来设置图形的透明度,结果在ie下出现了描边锯齿。

1
2
3
4
5
6
7
8
9
10
11
<style type="text/css">
.shape {
opacity: 0.5;
filter: alpha(opacity=50)
}
</style>

<v:shape class="shape" path="xxx">
<v:fill color="red"></v:fill>
<v:stroke color="red"></v:stroke>
</v:shape>

起初还以为是vml的数字精度问题导致的,后来排查了大半天才发现是使用了滤镜透明导致的。

改成vml元素的opacity属性才干掉了锯齿:

1
2
3
4
<v:shape class="shape" path="xxx">
<v:fill color="red" opacity="0.5"></v:fill>
<v:stroke color="red" opacity="0.5"></v:stroke>
</v:shape>