二分之一

Just Jason's Blog

javascript

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 »

实现跨域通信(跨文档消息传输)的几种方法(crossMessageEvent.js)

最近两天为实现一个跨域通信的问题,对这个问题进行了相关的学习,心得一二,在此分享。

window.postMessage()方法

HTML5给我们带来了安全的跨域通信接口,即window.postMessage()方法。它方法原型是:

window.postMessage(msg, domain);

该方法的浏览器支持情况:E8+, FF3+, Chrome, Safari,且在IE下,msg参数必须是string,不能是object.由此可见,我们只要考虑IE6,IE7下的跨域实现。

一、方案一

使用window.postMessage + window.opener实现,该方式是利用IE6,7 opener hack的方式实现跨域,可以算一个安全漏洞。

实现方式:

www.a.com/a.html

var otherWindow = document.getElementById("ifr_a").contentWindow; //ifr_a为嵌套b.html的iframe ID
otherWindow.opener={
    postMessage:function(str){
        alert(str);
    }
}

www.b.com/b.html

parent.opener={
    postMessage:function(str){
        alert(str);
    }
}

发送消息:

window.opener.postMessage(message);

这样目标页面就能收到消息了。

我做了一下JS的封装,大家可以直接下载使用:crossMessageEvent_opener.js

下载:crossMessageEvent_opener.js

otherWindow:为目标窗口的window对象
message:消息内容,可以是object
targetOrigin:目标窗口的域 [可选]

CrossMessageEvent.receiveMessage(funciton(event){
alert(event.data); //event.data为message的内容
});

该方法的优点:

不需要使用代理页面,简单直接。

该方法的缺点:

只要打过微软的安全补丁.kb2497640就不能用了。

Read more »

js容易被忽略的基础:函数语句和函数表达式的区别及与AS3的区别

在JS中,定义函数有两种方式,函数语句和函数表达式;

函数语句定义:

function testB(){
    console.log("B");
}

函数表达式定义:

var testA = function(){
    console.log("A");
}

1、作用域提升

在定义位置上,函数语句的方式定义,会将其作用域名提升至顶端,而函数表达式定义不会,必须先定义后执行。看下面的例子:

testB();
testA();
var testA = function(){
    console.log("A");
}
function testB(){
    console.log("B");
}

testA无法执行,因为找不到定义的函数,要想testA执行,必须将它的函数表达式定义放到执行时的前面。

2、this关键词的指向

在JS中,函数语句定义和函数表达式定义,this关键词都会指向其运行时的引用,两者没有区别。 而在AS3中,函数语句定义中的this始终指向当前函数定义的域,而函数表达式定义中的this会随着附加对象的变化而变化,且可以使用call()apply()改变其this的指向。

这一点区别非常重要,特别对于js和as同时使用的前端开发来讲,掌握两者的其础知识,能避免你犯错!

Read more »

JS判断数组类型的两种方法

一、构造函数法

在JS中,虽然没有严格的面向对象编程,但程序的设计还是有面向对象的味道。所有引用类型的数据,都是基于object;Array类型的数据,typeof时也会显示object;这给我们判断array类型,带来了不便。

细想一下array的创建过程,var arr = new Array(1,2,3);var arr = [1,2,3];实际上是创建了一个Array对象的实例,也就是说实例所对应的构造函数应该是Array;根据此原理,判断方法如下:

function isArray(object){
    return object && typeof object==='object' &&
            Array == object.constructor;
}

注意:

该种判断方法,被判断的array必须是在当前页面声明的!比如,一个页面(父页面)有一个框架,框架中引用了一个页面(子页面),在子页面中声明了一个array,并将其赋值给父页面的一个变量,这时判断该变量,Array == object.constructor;会返回false;

原因:

二、特性判断方法

即然上述方法,存在一定的缺陷,我们可根据数组的一些特性来判断其类型,代码如下:

function isArray(object){
    return  object && typeof object==='object' &&   
            typeof object.length==='number' && 
            typeof object.splice==='function' &&   
             //判断length属性是否是可枚举的 对于数组 将得到false 
            !(object.propertyIsEnumerable('length'));
}

有length和splice并不一定是数组,因为可以为对象添加属性,而不能枚举length属性,才是最重要的判断因子。

Read more »

推荐两个JS框架:jLinq、jquery.filedrop

一、jLinq

jLinq 是一个用来编写JavaScript对象数组查询的JavaScript库,可以对数组对象执行类似于LINQ风格的查询。

项目主页:http://www.hugoware.net/Projects/jLinq

二、jquery-filedrop

filedrop是一个html5图片拖拽上传的JS框架,能批量将电脑上的图片拖拽至浏览器,读取图片的二进制,并组装成post包,配合后台程序完成图片上传。

使用HTML5上传文件其实综合使用了3种技术,新的File Reader API,还有新的Drag&Drop API,以及AJAX技术(包含2进制的数据传输),filedrop对这三个功能进行的了整合封装。

项目地址:https://github.com/weixiyen/jquery-filedrop

Read more »

Easyui实现datagrid绑定JS本地对象(可不请求URL,不生成JSON)

初次接触easyui,使用datagrid时绑定数据时,大多人骂他的设计很烂,一定要在URL中指定一个json文件,或者请求一个服务器端动态生成的json程序,而在实际的开发中,后台程序很少愿意给到完全符合前台开发理想中的数据结构。

其实不然,我们接触一个新的东西时,遇到问题,总是习惯于到搜索引擎去寻求答案,而不愿意从API中找到答案,当然大家没这么多时间耗在这么长的英文API中。

easyui,datagrid使用,其实可以读取JS本地拼接组合的JSON对象的。

<table id="tt"></table>
//仅做一些基本的设置,不设置URL属性
$('#tt').datagrid({
    width:300,
    heigth:"auto",
    fitColumns:true
});
//绑定本地的JS对象
var jsdata = {total:1,rows:[{name:"",value:""}]}
$('#tt').datagrid("loadData",jsdata);

jQuery EasyUI中文帮助手册(API):http://www.phptogether.com/juidoc/ jQuery EasyUI英文官方手册(API):http://www.jeasyui.com/documentation/index.php

Read more »

JS计算圆周上N个等分点的坐标

用canvas做一个loading icon,需要用到圆周上等分点坐标的计算,算法如下:

var loadPoint = []; //结果
/*
*求圆周上等分点的坐标
*ox,oy为圆心坐标
*r为半径
*count为等分个数
*/
function getLoadPoint(r,ox,oy,count){
    var radians = (Math.PI / 180) * Math.round(360 / count); //弧度
    for(var i = 0; i < count; i++){
        var x = ox + r * Math.sin(radians * i);
        var y = oy + r * Math.cos(radians * i);
        loadPoint.unshift({x:x,y:y}); //为保持数据顺时针
    }
}

Read more »

Function中的扩展方法bind()

js bind 函数 使用闭包保存执行上下文

bind()主要具有两个重要作用:

(1)一般地,方法中的this关键字总是指向调用此方法的对象,这就造成this显得很不稳定,而使用bind()方法能够保证无论什么时候调用此方法,this关键字总是指向你所要的对象.

(2)提供两次添加参数的机会.第一次是在使用bind()方法的时候,第二次是调用bind()方法返回的句

prototypejs框架中的实现方式:

Function.prototype.bind = function() {
    var __method = this;
    var args = Array.prototype.slice.call(arguments);//将arguments转换为数组
    var object=args.shift(); //截取第一个
    return function() {
        return __method.apply(object,
             args.concat(Array.prototype.slice.call(arguments))
    );
    }
}

用法实例:

var name = "window";
var obj = {
    name: 'JSON',
    getName: function() {
        alert(this.name);
    }
};
function runFun(fun) {
    fun();
}
var getName2 = obj.getName.bind(obj);
runFun(obj.getName); //window
runFun(getName2); //JSON

Read more »

通过匿名函数实现JS的代码封装(类封装)

JS没有严格的类似JAVA的类概念,但可以通过原型链实现类。

通常意义上,推荐使用在构造函数中接受属性值,在原型链上注册方法属性。详情可参考《JavaScript高级程序设计(第2版)》

类似以下代码:

var myClass = function(a, b, c){
    this.a = a;
    this.b = b;
    this.c = c;
    // 构造函数
}

myClass.prototype = {
    f1: function(){alert(this.a);},
    f2: function(){alert(this.b);},
    f2: function(){alert(this.c);}
    //该类的方法
}
var classA = new myClass(1,2,3);
classA.f1();

匿名函数

顾名思义,匿名函数就是没有实际名字的函数。

大家知道小括号的作用吗?小括号能把我们的表达式组合分块,并且每一块,也就是每一对小括号,都有一个返回值。这个返回值实际上也就是小括号中表达式的返回值。所以,当我们用一对小括号把匿名函数括起来的时候,实际上小括号对返回的,就是一个匿名函数的Function对象。因此,小括号对加上匿名函数就如同有名字的函数般被我们取得它的引用位置了。所以如果在这个引用变量后面再加上参数列表,就会实现普通函数的调用形式。

(function(){alert(“匿名函数”);});

但小括号返回的仅是函数表达式,函数并没有运行起来。要运行函数表达式在后再再加上();

变成 (function(){alert(“匿名函数”);})();

这样就产生了一个困扰,这样写会产生闭包吗?大家都知道闭包对于GC的垃圾回收机制有影响,建议少用闭包。

下面我们就来探讨一下。

以我的理解来说吧。是否应用了闭包特性,必须确定该段代码有没有最重要的要素:未销毁的局部变量。

只能说这种写法有闭包的特性,只否形成闭包,还要看有没有未销毁的局部变量。

匿名函数封装类

(function(){

    var myClass = function(a, b, c){
        this.a = a;
        this.b = b;
        this.c = c;
        // 构造函数
    }

    myClass.prototype = {
        f1: function(){alert(this.a);},
        f2: function(){alert(this.b);},
        f2: function(){alert(this.c);}
        //该类的方法
    }

    window.myClass = myClass;
})();
var classA = new myClass(1,2,3);
var classB = new myClass(10,20,30);
classA.f1();
classB.f1();

其中window.myClass = myClass;这一段,也可以使用return 抛可供调用的API接口。

Read more »

javascript中的几个小技巧及原理

以下的几个小技巧,其实考察的是对JS基础知识的掌握和理解。基础的东西一定要打牢固,才能向使你的编码能力有台阶性的上升。

1、简短取当前时间戳。

普通青年的做法:

var time = new Date().getTime();

文艺青年的做法:

var time = (+(new Date));
//或
var time = +(new Date);

效果是一样的,但是文艺青年的做法,明显优雅一些,不过可读性视各位的基础而定。

原理:

大家知道小括号的作用吗?小括号能把我们的表达式组合分块,并且每一块,也就是每一对小括号,都有一个返回值。(new Date)其实就是返回当前的Date对象。

一元加操作符(+),放在数字前面,对数值不会产生任何影响。但放在非数值类型的前面,相当于Number()转型函数。+(new Date)就返回了时间戳数字。但为什么外面还需要一对括号呢,如果用于赋值操作,可有可无,但用于字符串连接操作时,一定要加上。

2、布尔操作符的妙用

判断一个字符串为空 var str = “”;

普通青年的做法:

if(str==''){
    alert("字会串是空的哦!");
}

文艺青年的做法:

if(!str){
    alert("字会串是空的哦!");
}

原理:

逻辑非(!)操作符,放在值前面,无论这个值是什么数据类型,这个操作符都会返回一个布尔型,然后再对其求反。 两个”!!”,实际上就相当于应用Boolean()函数转型。

3、逻辑与操作符(&&)的妙用

a(),和 b(); b的执行需a()返回值为true才能执行,否则不执行。

普通青年的做法:

if(a()){
    b();
}

文艺青年的做法:

a() && b();

原理:

逻辑与属于短路操作,如果第一个操作数能够决定结果,那么不会对第二个操作数进行求值。 当a();返回false时,就注定整个表达式为false,无需运行b();

Read more »