javascript中constructor的作用

这里其实并不是要讲 constructor 的作用。 
而是为了要分析这句代码的含义:

f.prototype.constructor = f

经常会在别人写的类里面看到这句代码(其中f为function名称)。

为了搞清楚这句代码的含义,首先要大概先了解constructor的作用。 
在上一篇文章 《javascript中关于new的理解》 ,中,我们知道了如何创建一个构造函数。 
文章重点主要是侧重new的用法,而省去了很多其他相关联的知识点。

那么在创建构造函数的时候,会同时创建这个构造函数的 prototype 属性,(更准确的说应该是每个函数都有一个默认的prototype 属性),而prototype里的constructer 则指向构造函数。 
也就是说 constructor始终指向创建当前对象的构造函数 。记住这个点。 
如下面代码:

function Person(name) {
	 this.name = name;
 };

Person.prototype.getName = function() {
	return this.name;
};

//实例化对象
var p = new Person("ZhangSan");
//查看结果:Person的constructor始终是指向Person的
console.log(p.constructor === Person);  // true
console.log(Person.prototype.constructor === Person); // true

那么也就是说

f.prototype.constructor = f

这句代码是多余的,因为默认情况下就是这样。

但是 ,当时当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是 覆盖 ), constructor就指向Object里。

看下面的代码:

function Person(name) {
	this.name = name;
};
Person.prototype = {
	getName: function() {
		return this.name;
	}
};
var p = new Person("ZhangSan");
console.log(p.constructor === Person);  // false
console.log(Person.prototype.constructor === Person); // false
console.log(p.constructor.prototype.constructor === Person); // false

注意这里是直接修改了prototype,而不是在prototype上加方法。

为什么会发生这种情况?因为 constructor始终指向创建自身的构造函数 ,那上面那段代码实际等价为:

Person.prototype = new Object({
    getName: function() {
        return this.name;
    }
});

这样的话,就易于理解了。为什么prototype={}之后,constructor指向就发生了变化。

为了使构造函数的实例的创建者保持正确的引用,就要用这句代码来修正引用

f.prototype.constructor == f

再引用网上的一张图,也许理解起来更直观:

图片来源: http://www.nowamagic.net/librarys/veda/detail/1642

最后总结下:

f.prototype.constructor = f,这句代码只有这样写 f.prototype ={} 的情况下才使用。 
也许你会问,我不加这句好像也没什么影响啊。。 
确实,这种“高级代码”对于我等普通的P民几乎没作用,因为我们写不出那些高上大的代码。一般写框架、写类库的时候也许会用到。

但是为了保持良好的编码习惯,还是加一下比较好,呵呵。

javascript中关于new的理解

Javascript中,实例化一个对象,会用到new关键字。

经常有人会问我,对于一个函数,什么时候该使用new关键字。

在回答这个问题之前,需要先了解清楚new的本质,在调用new Function的时候,new做了什么操作。

先看如下代码:

// 定义类 类名字是 classA
function classA(){
	this.name=1;
}
classA.prototype.show = function(){
	alert(this.name);
};
// 用new实例化
var b = new classA();
b.show();

var b = new classA();

这句中,new做了以下几件事情。 
1、创建一个新的对象,这个对象的类型是object; 
2、查找class的prototype上的所有方法、属性,复制一份给创建的Object 
3、将构造函数classA内部的this指向创建的Object 
4、创建的Object的__proto__指向class的prototype 
5、执行构造函数class 
6、返回新创建的对象给变量b

这个流程应该比较好理解的。这里再解释一下: 
1、构造函数:我们一般把new 后面的函数称为构造函数,如new classA(),其中classA就为构造函数 
2、第四点的__proto__,可能比较难理解。 
每个对象都会在其内部初始化一个属性,就是__proto__,可以在chrome中的调试器里写个对象查看下。 当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性 ,这个__proto__又会有自己的__proto__,于是就这样一直找下去,也就是我们平时所说的原型链的概念。

当我们调用b.show()时,首先b中没有show这个属性,于是,它就需要到它的__proto__中去找,也就是ClassA.prototype, 
而我们在上面定义了ClassA.prototype.show=function(){}; 于是,就找到了这个方法。

再用下面的代码来理解

var b = {}
b.__proto__ =  ClassA.prototype
ClassA.call(b)

最后再用一句话总结:new关键字以ClassA()为模板创建了一个新的对象,它复制了ClassA构造器中的所有成员变量,同时this指向新创建的对象。

有2点需要注意: 
1、如果构造函数内没有返回值,则默认是返回this(当前上下文),要不然就返回 任意非原始类型值 。 
2、如果不用new关键字,如

var b = classA();

则classA值会返回undefined,并且this(执行上下文)是window对象。 
也就是说如果你不new的话,this指的就是window全局对象了。 
如下面代码:

// 定义类 类名字是 classA
function classA(){
	this.name=1;
}
//执行classA
classA();
//看下name是undefined还是1
name //返回1

看到这里,相信绝大多数人应该都理解了new的用法了。

jquery插件及zepto插件 写法异同

jquery插件及zepto插件,写法上有些区别。

区别点: 
1、自定义事件的命名空间 
jq的时间命名空间是用点“.”,而zepto是用冒号“:” 

//jquery
$(this).trigger('cusevent.pluginname');

//zepto
$(this).trigger('cusevent:pluginname');

2、data() 方法 
jq的data方法非常强大,可以存储字符串、对象、函数等一切js数据 
而zepto的data方法则非常简陋,只能纯一下字符串。 
由于写插件时,常用data方法来缓存插件实例化后的内容,所以这里需要做一下兼容修改。

// i is simply a counter, the rest 
// of what is stored will be instances
$.waiting.lookup = {
  i: 0
};

// store the new instance.. $t=$(this)
$.waiting.lookup[++$.waiting.lookup.i] = new $.waiting($t, o);
$t.data('waiting', $.waiting.lookup.i);

// retrieve the instance
var inst = $.waiting.lookup[$(this).data('waiting')];

最后附上,JQ插件的编写模板,写插件的时候就不用考虑代码组织结构了。

/**
 * Created by hugohua on 14-4-1.
 * jQuery plugin template
 */

/**
 * 将插件封装在一个闭包里面,防止外部代码污染  冲突
 */
(function ($) {
    /**
     * 定义一个插件 Plugin
     */
    var Plugin,
        privateMethod;  //插件的私有方法,也可以看做是插件的工具方法集

    /**
     * 这里是插件的主体部分
     * 这里是一个自运行的单例模式。
     * 这里之所以用一个 Plugin 的单例模式 包含一个 Plugin的类,主要是为了封装性,更好的划分代码块
     * 同时 也 方便区分私有方法及公共方法
     * PS:但有时私有方法为了方便还是写在了Plugin类里,这时建议私有方法前加上"_"
     */
    Plugin = (function () {

        /**
         * 插件实例化部分,初始化时调用的代码可以放这里
         * @param element 传入jq对象的选择器,如 $("#J_plugin").plugin() ,其中 $("#J_plugin") 即是 element
         * @param options 插件的一些参数神马的
         * @constructor
         */
        function Plugin(element, options) {
            //将dom jquery对象赋值给插件,方便后续调用
            this.$element = $(element);

            //将插件的默认参数及用户定义的参数合并到一个新的obj里
            this.settings = $.extend({}, $.fn.plugin.defaults,options);
            //如果将参数设置在dom的自定义属性里,也可以这样写
            this.settings = $.extend({}, $.fn.plugin.defaults, this.$element.data(), options);

            //初始化调用一下
            this.init();
        }

        /**
         * 写法一
         * 插件的公共方法,相当于接口函数,用于给外部调用
         */
        Plugin.prototype.doSomething = function () {
            /**
             * 方法内容
             */
        };

        /**
         * 写法二
         * 将插件所有函数放在prototype的大对象里
         * @type {{}}
         */
        Plugin.prototype = {

            init:function(){
                console.log('init');
            },

            doSomething2:function(){

            }
        };

        return Plugin;

    })();

    /**
     * 插件的私有方法
     */
    privateMethod = function () {

    };

    /**
     * 这里是将Plugin对象 转为jq插件的形式进行调用
     * 定义一个插件 plugin
     */
    $.fn.plugin = function (options) {
        return this.each(function () {
            var $me = $(this),
                instance = $me.data('plugin');
            if(!instance){
                //将实例化后的插件缓存在dom结构里(内存里)
                $me.data('plugin', new Plugin(this, options));
            }

            /**
             * 优雅处: 如果插件的参数是一个字符串,则 调用 插件的 字符串方法。
             * 如 $('#id').plugin('doSomething') 则实际调用的是 $('#id).plugin.doSomething();
             * doSomething是刚才定义的接口。
             * 这种方法 在 juqery ui 的插件里 很常见。
             */
            if ($.type(options) === 'string') instance[options]();
        });
    };

    /**
     * 插件的默认值
     */
    $.fn.plugin.defaults = {
        property1: 'value',
        property2: 'value'
    };

    /**
     * 优雅处: 通过data-xxx 的方式 实例化插件。
     * 这样的话 在页面上就不需要显示调用了。
     * 可以查看bootstrap 里面的JS插件写法
     */
    $(function () {
        return new Plugin($('[data-plugin]'));
    });
})(JQuery);

IE7-8 PNG24加透明opacity在Jquery动画中出现黑边的解决方法

这个问题 相信不少做JQ动画的童鞋都遇到过。在页面上实现一些动画效果,用PNG24的图片。经常会出现黑边。

JQuery动画的淡入淡出效果,用在PNG24的图片上,在IE7、IE8下会出现黑边框。

有些人觉得很奇怪,为什么屌丝IE6正常,反而在IE7、8下却有黑边呢。

其实问题出在filter属性上。IE6引用PNG24的图片的方式是:

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img24.png');

所以避免了这个黑边问题。

网上也有一些JS插件解决黑边问题。但效果并不理想。经过多次测试,最终解决方案如下:

在使用PNG24的图片外再嵌套一层DIV,用于设置透明度。同时IE下PNG24图片不使用background来引用。而使用filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’img24.png’);的方式。

相关代码:
html

<div class="warp"> <div class="img24"></div> </div> 

css

.warp {
filter:alpha(opacity=20);
}

//这里是单独对IE678设置的样式,chrome等其他高级浏览器还是照样用background引用
.img24 {
background:none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='img24.png');
width:100px;
height:100px;
}

Backbone 介绍及学习资料索引

Backbone 是一款构建Javascript应用程序的优秀类库(lib)。网上大部分文章介绍时,都说是一款重量级MVC应用框架,但个人感觉,算是比较轻量的lib了。它比较简洁,A但同时提供了很大的灵活性,依赖underscore.js 提供了非常丰富的基础功能操作。

本文目的不在介绍backbone,而是根据这1周的学习,整理一部分国内外资料给初学者、入门者学习。

1、API文档及源码

Backbone托管在https://github.com/documentcloud/backbone/,可在这里下载最新的源码级example

英文API文档:http://backbonejs.org/

中文API文档:http://www.csser.com/tools/backbone/backbone.js.html   翻译时间比较久,部分API可能有变化,但总体还是和最新版差别不大,如果英文不好的童鞋可先看看这个中文版API,然后再对照英文最新版看看。

中文Underscore.js文档:http://www.css88.com/doc/underscore/

2、业内关于backbone的一些介绍及实例说明:

backbone.js 初探  介绍性不多,主要是以一个例子来说明backbone的整个处理流程。

Backbone.js入门学习笔记目录   作者很好的整理了一系列的入门学习资料,可以说是相当详细的,看完这系列后,应该说对backbone有一定的认识和理解了。

Backbone Tutorials E文的backbone学习资料,让你认识backbone是什么以及如何使用。也有几个实例,蛮不错的

Developing Backbone.js Applications   这篇文章长得都可以出书了,可以说是,从简入深,从入门到精通。

3、backbone实例、Demo

官方介绍的实例:http://backbonejs.org/#examples  非常有代表性

Todo是实例:https://github.com/documentcloud/backbone/  官方例子,肯定非常经典,虽然简单,但已包含了backbone的基本功能。

关于todos的源码解析:
http://www.the5fire.net/7-backbone-todos-1.html
http://www.xiaoqiang.org/javascript/backbone-js-todo.html
这2篇文章较好的对源码进行分析,通过从网站下载的todos源码,发现作者对源码进行了一些小修改,但 也不影响,总体还是没多大修改的。

 Build a Contacts Manager Using Backbone.js: Part 1 中文翻译了part1 ,part2没有翻译,但看起来也不难,代码多,看代码就基本能理解意思了。(本人E文太si)

类似聊天室的Demo
http://thomasdavis.github.com/2011/02/01/backbone-introduction.html

who is your friends  作者很粗糙的翻译了下,还没翻译完整,建议看E文原版。

Wine Cellar Tutorial    这个酒窖例子相当不错,非常完整,包含了服务器端。一共分了3篇文章来介绍,part2part3

非常难得的是,作者在后来又写了一篇文章,是对之前这个examle的改进:http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/

顺便说一下这个例子的php版用的是Slim做rest api,slim是个微型的rest api框架,也是非常好用的。

4、高级实例

高级实例是相当于一个在线可运行的app了,代码已经不局限于backbone。(在做一个web javascript应用时,可能会用到其他的一些lib)

http://bbclonemail.heroku.com/#inbox/sdf908f67hjf9sf
http://backbonetraining.net/resources
http://kroltech.com/2013/12/boilerplate-web-app-using-backbone-js-expressjs-node-js-mongodb/
http://kroltech.com/2013/03/building-a-web-app-using-backbone-js-and-require-js-part-1/

6、backbone文件组织及管理

这部分建议和淘宝前端玉伯写的模块加载器seajs一起使用,

seajs介绍:http://seajs.org/

在国外则比较流行requireJs

Backbone 利用Modules 来组织你的程序(require.js )

Web application with backbone.js and requirejs packages, requirejs optimizer  看打勾的那个评论。

7、源码分析

最后肯定少不了源码分析。[原创]Backbone源码分析-Backbone架构+流程图

最后不得不说,看是没用的,看只是让你了解和熟悉,一定要自己动手去写,才能切实感受到其中的内涵。