CommonJs
CommonJs规范给javascript制定了一个美好的愿景-----希望javascript能够在任何地方运行。
CommonJs是一种规范,NodeJs是这种规范的实现。Node借签CommonJs的Modules规范实现了一套非常易用的模块系统,NPM对Packages规范的完好支持使得Node应用在开发过程中事半功倍。
CommonJs的模块规范
CommonJs对模块的定义十分简单,主要分为模块引用,模块定义和模块标识3个部分。
模块引用:
Var math=require(“math”);
模块定义:
提供Exports对象用于导出当前模块的方法或者变量,并且它是唯一的导出出口。
CommonJs构建的这套模块导出和引入机制使得用户完全不比要考虑变量污染;、
例如:
// math.js
exports.add = function () {
var sum = 0,
i = 0,
args = arguments,
l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
在另一个文件中,通过require()方法引入模块后,就能调用定义的属性和方法了。
// program.js
var math = require('math');
exports.increment = function (val) {
return math.add(val, 1);
};
模块标识:
模块标识其实就是传递给require()方法的参数。
AMD和CMD的区别:
1) 对于依赖的模块,AMD是提前执行,CMD是延迟执行
2) CMD推崇依赖就近,AMD推崇依赖前置
- // CMD
- define(function(require, exports, module) {
- var a = require('./a')
- a.doSomething()
- // 此处略去 100 行
- var b = require('./b') // 依赖可以就近书写
- b.doSomething()
- // ...
- })
- 10.
11. // AMD 默认推荐的是
12. define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
- 13. a.doSomething()
- 14. // 此处略去 100 行
- 15. b.doSomething()
- 16. // ...
17. })
事件
DOM事件流的三个阶段包括:事件捕获阶段,处于目标阶段,事件冒泡阶段。
Opera,Firefox,Chrome和Safari都支持Dom事件流,IE不支持DOM事件流。
事件冒泡: 即事件开始由具体的元素接收,依次传播到较为不具体的节点;
IE一般用window.event.cancelBubble=true来阻止事件冒泡。
非IE一般用 event.stopPropagation()来阻止事件冒泡
事件冒泡的顺序是:具体 div----》Element body --》Element html --》Document
事件捕获
事件捕获的顺序和IE完全相反:即:
DocumentàElement html àElement bodyàElement div
事件处理程序
事件就是用户或者浏览器执行的某种动作,有以下三种事件处理程序:
1) html事件处理程序 ,直接在控件上绑定函数名称(缺点:html与javascript代码紧密耦合)
2) Dom0级事件处理程序,获取具体控件,然后为获取的控件添加事件。(这种方式简单,具有跨浏览器的优势)
这时候的事件处理程序师在元素的作用域中运行的。即:程序中的this引用当前元素。
3) DOM2级事件处理程序,FireFox,Safari,Chrome,Opera都支持Dom2级事件处理程序,而IE不支持Dom2
DOM2级事件处理程序,定义addEventListener()和removeEventListener()用来处理指定和删除事件的程序操作。
这两个方法接受:参数,处理的函数,布尔值;
布尔值为true,表示在捕获阶段调用事件处理程序。
如果为false ,则在冒泡阶段调用事件出来程序。
删除事件的时候,要指定具体的函数名称,对匿名函数无效。
IE事件处理程序;
IE事件出来程序使用了attachEvent()和detachEvent()
[javascript] view plain copy
- var btnIE=document.getElementById("myBtnIE");
- btnIE.attachEvent("onclick",function(){alert(this===window);});
- btnIE.attachEvent("onclick",function(){alert("hello,this is second click");});
- //IE事件处理程序也可以添加多个事件处理程序,但是这些事件处理程序师以相反的顺序被触发
- //即上面的会先弹出"hello,this is second click",然后再弹出true
- //使用attachEvent()添加的可以通过detachEvent()来移除,条件是必须提供相同的参数,因此添加的匿名函数也不可以移除
- btnIE.detachEvent("onclick",function(){});//无效<span style="font-family:Arial,Verdana,sans-serif;">
- </span>
currentTarget是事件的绑定者 ,target是事件的触发者
谈谈性能优化问题
代码层面:避免使用css表达式,避免使用高级选择器,通配选择器。
缓存利用:缓存Ajax,使用CDN,使用外部js和css文件以便缓存,添加Expires头,服务端配置Etag,减少DNS查找等
请求数量:合并样式和脚本,使用css图片精灵,初始首屏之外的图片资源按需加载,静态资源延迟加载。
请求带宽:压缩文件,开启GZIP,
代码层面的优化
- 用hash-table来优化查找
- 少用全局变量
- 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能
- 用setTimeout来避免页面失去响应
- 缓存DOM节点查找的结果
- 避免使用CSS Expression
- 避免全局查询
- 避免使用width(width会创建自己的作用域,会增加作用域链长度)
- 多个变量声明合并
移动端性能优化
- 尽量使用css3动画,开启硬件加速。适当使用touch事件代替click事件。避免使用css3渐变阴影效果。
闭包的理解
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染。缺点是闭包会常驻内存中,会增大内存的使用量,使用不当为造成内存泄漏。
闭包的三个特征:
1, 函数嵌套函数
2, 函数内部可以引用外部的参数和变量
3, 参数和变量不会被垃圾回收机制回收。
函数
函数声明和函数表达式之间的主要差别:
1) 函数声明会在代码执行之前被加载到作用域中,而函数表达式则是在代码执行到那一行的时候才有的定义
2) 函数的声明给函数制定一个名字,而函数表达式是创建一个匿名函数。
模式
1) 最简单的模式:创建一个Object实例
缺点:同一个接口创建很多对象,会产生大量的重复代码。
2) 工厂模式,工厂模式解决了创建多个相似对象的问题,但是没有解决对象识别的问题(因为返回的时object对象,而不是一个具体的对象)
3) 构造函数模式(缺点:每个方法都要在实例上重新创建一遍),为了解决这个问题,把函数移到了构造函数的外部,这样又导致了另外一个问题,多个全局函数,让自定义的引用类型没有封装性
4) 原型模式: 使用原型对象的好处就是可以让所有的实例共享它所包含的属性和方法。
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性。
每一个函数都包含prototype属性,这个属性指向一个对象的引用,这个对象称为原型对象。
原型模式最大的问题是由其共享本质造成的,对于包含引用类型的值的属性来说,问题就比较突出,因为改变一个实例的引用,所有的都改变了。所以比较常用的方式,就是组合使用构造函数模型和原型模式,构造函数用于定义实例属性,而原型模式用于定义方法和共享属性。
例如:
function Teacher(name,age){
this.name=name;
this.age=age;
this.friends=["alice","stone"];
}
Teacher.prototype={
constructor:Teacher,//如果不重新设置此属性,则为Object
sayName:function(){
alert(this.name);
};
};
var teacher1=new Teacher("hello",22);
var teacher2=new Teacher("Greg",25);
teacher1.friends.push("Van");
alert(teacher1.friends);//"alice","stone","Van"
alert(teacher2.friends);//"alice","stone"
alert(teacher1.friends===teacher2.friends);//false
alert(teacher1.name===teacher2.name);//true
创建继承链;
只需要将对象实例作为要继承该对象实例的函数的prototype的属性值;
即:chef.prototype=new Person();
//创建继承链
var Person = function() {
this.bar = 'bar';
};
Person.prototype.foo = "foo";
var chef = function() {
this.goo = "goo";
};
chef.prototype = new Person(); //创建继承
var cody = new chef();
console.log(cody.foo); //输出foo
console.log(cody.goo); //输出goo
console.log(cody.bar);//输出bar