二分之一

Just Jason's Blog

javascript设计模式之Observer(观察者)模式

没空讲原理了,写了一个DEMO供大家学习,先上一段核心代码,然后附上DEMO。

请查看DEMO,更详细的理解Observer(观察者)模式

DEMO:test.html

/**************订阅者/观察者/subscribe************/
function ObserverList(){
    this.observerList = [];
};

//添加
ObserverList.prototype.Add = function(obj){
    if(this.IndexOf(obj,0)==-1){
        return this.observerList.push(obj);
    }else{
        this.observerList;
    }
};

//清空
ObserverList.prototype.Empty = function(){
    this.observerList = [];
};

//统计
ObserverList.prototype.Count = function(){
    return this.observerList.length;
};

//获取
ObserverList.prototype.Get = function(index){
    if(index>-1 && index<this.observerList.length){
        return this.observerList[index];
    }
};

//插入
ObserverList.prototype.Insert = function(obj,index){
    var pointer = -1;
    if(index===0){
        this.observerList.unshift(obj);
        pointer = index;
    }else if(index === this.observerList.length){
        this.observerList.push(obj);
        pointer = index;
    }
    return pointer;
};

//查询位置
ObserverList.prototype.IndexOf = function(obj,startIndex){
    var i = startIndex,pointer = -1;
    while(i<this.observerList.length){
        if(this.observerList[i]===obj){
            pointer = i;
        }
        i++;
    }
    return pointer;
};

ObserverList.prototype.RemoveIndexAt = function(index){
    if(index===0){
        this.observerList.shift();
    }else if(index===this.observerList.length-1){
        this.observerList.pop();
    }else{
        this.observerList.splice(index,1);
    }
}

//扩展对象
function extend(obj,extension){
    for(var key in obj){
        extension[key] = obj[key];
    }
}

/**************发布者/目标/publish****************/
function Subject(){
    this.observers = new ObserverList();
}

Subject.prototype.AddObserver = function(observer){
    this.observers.Add(observer);
};

Subject.prototype.RemoveObserver = function(observer){
    this.observers.RemoveIndexAt(this.observers.IndexOf(observer,0));
    console.log(this.observers);
};

Subject.prototype.Notify = function(context){
    var observerCount = this.observers.Count();
    for(var i=0;i<observerCount;i++){
        this.observers.Get(i).Update(context);
    }
};

Read more »

使用 SourceMap 来进行压缩后的代码调试,以underscore为例

JS发布后通常会经过压缩和混淆,所有代码被压缩成一行代码,如果发生错误,无法定位错误,SourceMap因此而生。

说起SourceMap,不得不说说uglifyjs,uglifyjs是nodejs下一款优秀的JS压缩优化工具,支持SourceMap的生成。

一、uglifyjs的使用及SourceMap文件的生成方法

1、安装nodejs:http://nodejs.org,windows下直接安装即可,安装好后自带npm.
2、打开CMD,输入node -v查看,nodejs是否安装成功,如果成功会返回一个版本号。
3、安装uglifyjs:执行命令:npm install uglify-js -g
4、uglifyjs使用方法及API:https://github.com/mishoo/UglifyJS2
5、压缩JS并生成SourceMap文件

uglifyjs underscore.js --source-map underscore.js.map
--source-map-root ./ -m -c -o underscore-mini.js

会生成两个文件:

二、用 SourceMap 调试

有了SourceMap文件,放置underscore-mini.js同一目录,引用underscore-mini.js时,就可以调试,看到未压缩的代码

调试方法: 打开chrome – F12(打开调试工具)- 调试工具右下角有一个设置,打开设置 – General – Enable source maps

这样就打开了SourceMap调试功能。

在Sources面板下,左侧展开,就能看到SourceMap解出来的未压缩文件,多个压缩文件都可以看到。

三、SourceMap的原理解析

单说,Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。这无疑给开发者带来了很大方便。

1、SourceMap基本结构如下:

/assets/upload/20130723160149.png

2、重点在于mappings的解码

第一层是行对应,以分号(;)表示,每个分号对应一行代码;
第二层是位置对应,以逗号(,)表示,每个逗号对应转换后源码的一个位置。
第三层是位置转换,以VLQ编码表示,代表该位置对应的转换前的源码位置。

VLQ编码相关,请查询更多资料~~

Read more »

jQuery源码解读一:部份jQuery工具方法实现

jQuery作为前端最流行的类库,没有之一,源码必须得读一读。本博将不定期更新源码解读内容,如果解读不正确的地方,还请同学们在评论中指正。

本系列文章基于最新的jquery-1.9.1.js。

一、$.type() 判断js数据类型

用法:$.type(new Array()); //array

部份源码(截取关键部份,请忽略源码语法):

//生成typelist的map
class2type = {}
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

//每个对象实例都有toString方法
core_toString = class2type.toString

//主方法
type: function( obj ) {
    if ( obj == null ) {
        return String( obj );
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[ core_toString.call(obj) ] || "object" :
        typeof obj;
}

解读:

1、class2type生成后的内容为

var class2type = {
    "[object Boolean]":"boolean",
    "[object Number]":"number",
    "[object String]":"string",
    "[object Function]":"function",
    "[object Array]":"array",
    "[object Date]":"date",
    "[object RegExp]":"regexp",
    "[object Object]":"object",
    "[object Error]":"error"
}

2、core_toString使用的是对象实例的toString

所有继随自Object的对象都有toString方法,为什么一定要使用object.toString,因为array,function虽然有toString方法,但该方法进行了重写,array调用toString打印的数组成员用逗号隔开的字符串。这里使用的是{}.toString.call(obj);改变toString的this指向为object实例。jquery为什么使用的是class2type.toString.call,这样就可以少声明一个object。

var func = function(){};
var arr = [];
console.log({}.toString.call(func)); //[object Function]
console.log({}.toString.call(arr)); //[object Array]

这样就得到class2type的键名,以此判断数据类型。

Read more »

让IE6完美实现position:fixed并发布自己写的一个小插件jquery.fixed.js

在工作中,常碰到模态窗口、固定header、固定广告、固定go to top等等,都需要一个很重要的特性position:fixed,该特性在大多数浏览器下支持的还不错,只有IE6这个老大难,又调皮了。

遇到问题就解决问题,解决了问题就记录下,趁假期得空,把一些遇到的坑填平记录一下,同时分享给各位同学,好了,不多废话。

一、IE6下使用position:absolute代替position:fixed

使用绝对定位,很好理解,但是浏览器在调整时(滚动、缩放),left和top如何动态的计算其值呢?在IE6下CSS表达式(expression)可以帮我们解决难题,虽然IE8取消了该API,由于其它效率低,不建议使用。浏览器在调整时,会重新计算css expression,所以我们的问题就解决了。

CSS解决办法:

* html .header{
    position:absolute;
    left:expression(eval(document.documentElement.scrollLeft+10)+"px");
    top:expression(eval(document.documentElement.scrollTop+10)+"px");
}

JS解决办法:

expression对应在JS中的方法是style的setExpression方法,第一个参数是CSS属性名,第二个参数计算表达式字符串。

domThis.style.setExpression('left',
'eval((document.documentElement).scrollLeft + ' + 10 + ') + "px"');

二、修正IE6抖动bug

IE有一个多步的渲染进程。当你滚动或调整你的浏览器大小的时候,它将重置所有内容并重画页面,这个时候它就会重新处理css表达式。

因此虽然CSS进行了重新计算,需要fixed的元素位置也进行了正确的调整,但是会有一跳一跳的抖动感觉,这种体验很不好,如果浏览器调整的频繁,很伤眼。

好在,这个问题不是无解的,是“有药可医”的。

Read more »

记录一下IE6下的两个小坑(form post target iframe、void)及解决办法

一、IE6下使用form post target iframe进行POST跨域请求,如果设置了document.domain,POST请求发送不出去。

另外iframe的name属性要一次性写入,不能通过dom的方式修改,修改无效。

www.2fz1.com/a.html

<script type="text/javascript">
document.domain = "2fz1.com"
</script>
<iframe name="commentpost" id="commentpost"></iframe>
<form action="http://data.2fz1.com/data.php" method="post" target="commentpost">
    <textarea name="detail"></textarea>
    <input type="submit" class="publish_btn" value="提交">
</form>

原因分析:

1、IE6下,因为在父页面或在iframe页面中,只要设置了document.domain,无论是和当前域名相同还是根域名,均视为跨域。而我们使用form post到iframe时,IE6当作跨域给“拒绝访问”了。有人可能会说,可以给子页面设置document.domain,但是我们的子页面是变动的服务器程序,iframe的src如果是定死的就可以解决。

2、大概定位一下:IE6升级到IE7后默认禁用了“跨域浏览子框架”,但是IE7下不会禁用这种,但是把IE7卸载后回到ie6这个设置没改回原来默认的启用,导致ie6不允许form.target指向一个空的iframe。IETester下的IE6,也有同样的原因。

解决办法:

<iframe src="javascript:document.domain='xxx.ooo';void 0;"></iframe>

Read more »

CSS让网页整体变灰[为雅安地震祈福]

html{
    -webkit-filter: grayscale(100%);
    -moz-filter: grayscale(100%);
    -ms-filter: grayscale(100%);
    -o-filter: grayscale(100%);
    filter: grayscale(100%);
    filter: url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/
svg\'><filter id=\'grayscale\'><feColorMatrix type=\'matrix\' values=\'0.3333
 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1
 0\'/></filter></svg>#grayscale");
    filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
}

不过对firefox和flash支持不好,暂时没有总结出最完美的兼容方案。

Read more »

Javascript异步编程几种方式及Ajax串行执行探讨

由于JS是单线程语言,程序在同步执行时,如果耗时较长就会阻塞下面的进程,而异步编程则可以避免这个问题。异步编程在耗时长的操作中非常重要,比如连接网络文件,读取本地文件等。

Ajax就是经典的异步程序,但是多个ajax需要串行执行时,怎样才能优雅有序的执行呢?本文将探讨大规模异步ajax串行执行时的编程问题。

常用的几种异步编程方式有:【本文代码范例基于jquery】

一、回调函数

function a(callback){
    $.get("a.php",function(data){
        callback(data);
    });
}
function b(data){
    console.log(data);
}
a(b);

a执行完后,b再执行。这是典型的回调函数用法,但是回调函数代码高度耦合,代码可读性不高,而且比较混乱,如果回调流程比较长,需要从中减掉一个回调流程时,不易修改。

Read more »

jQuery deferred对象API详解及DEMO

jQuery在1.5开始引入deferred(延迟),简单说,deferred对象就是jQuery的回调函数解决方案。

jQuery1.5中,Deferred对象提供一种方式来注册多个回调,添加到自已管理的回调队列中,调用适当的回调队列,并转达同步或异步函数的成功或失败状态。

deferred对象有三种执行状态:未完成(pending),已完成(resolved)和已失败(rejected)

API概览:

deferred object = {
    always(alwaysCallbacks [, alwaysCallbacks])
    //延迟对象不管成功或失败都最终会执行该方法

    done(doneCallbacks)
    //延迟对象成功完成后调用

    fail(failCallbacks)
    //延迟对象失败后调用

    isRejected()
    //确定延迟对象是否已失败

    isResolved()
    //确定延迟对象是否已成功

    notify( args )
    //用来触发一个自定义事件fireEvent

    notifyWith(context, [args])
    //跟notify一样,但可以指定上下文

    pipe([doneFilter] [, failFilter] [, progressFilter] )
    //jQuery的1.8,deferred.pipe()方法已经被淘汰。
    //用deferred.then()替代

    progress( progressCallbacks )
    //用来监控函数执行过程,进度处理程序,见:notify 方法

    reject([args])
    //使延迟对象的状态变为失败,对应的回调函数绑定方法为fail。

    rejectWith(context, [args])
    //使用方法与reject一样,但是可以指定上下文,使用可以参考 resolveWidth

    resolve([args])
    //使延迟对象的状态变为成功,对应的回调函数绑定方法为done。

    resolveWith(context, [args])
    //使用方法与resolve一样,但是可以指定上下文

    state()
    //查询延迟对象的状态,有三种:pending resolved rejected

    then(doneCallbacks, failCallbacks [, progressCallbacks])
    //一种缩写,用法与done,fail一样

    promise([target])
    //在原来的deferred对象上返回另一个deferred对象,
    //这个新的deferred对象屏蔽了改变状态的方法。
}

Read more »

Github安装失败解决办法(网络问题)

配置如下hosts:

207.97.227.239 github.com
65.74.177.129 www.github.com
207.97.227.252 nodeload.github.com
207.97.227.243 raw.github.com
204.232.175.78 documentcloud.github.com
204.232.175.78 pages.github.com

Read more »

博客换主题了,新主题命名为:“Butterfly”(蝴蝶)

二分之一前端开发,经过周末两天的奋战,我的博客(2fz1.com)一年后终于换肤了,新主题命名“Butterfly”(蝴蝶),颜色选择有点丰富,一改去年的简朴,最大的特色是图标字体化,预计会加上更多的html5+css3应用。演示:

http://www.2fz1.com

Read more »