- 类型检测
typeof 一般用于js的基本数据类型(undefined,number,string,boolean。注意null检测的结构是object)检测,引用类型检测不准确。
instanceof 用于检测构造函数,一般引用类型数据类型检测可以检测出来,数组一般是用这种检测方式。但如果页面嵌套的比如iframe,这种检测也会出错。
Object.prototype.toStirng.call(检测的变量)这种检测方式是最不容易出错的。
- 作用域安全的构造函数
一般我们用js声明一个类是这样声明的:
function Student(name,age){ this.name=name; this.age=age; } var stu=new Student (“li lei”,20);
如果直接调用Student函数时this直接指向window对象,这样会导致name和age都声明到全局变量中,导致全局变量的污染。为了避免这种危险性,构建作用域安全构造函数,先判断this的类型。
function Student(name,age){ if(this instanceof Student){ this.name=name; this.age=age; } else{ return new Student (name,age) } }
这样直接调用Student函数返回的也是实例的对象。这种写法也有个问题,在继承类的时候要用call来调用父类的构造函数,但由于this指向的是子类导致this instanceof Student为false。
function Stu(){ Student.call(this,’name’,22); }
解决方案是用原型继承:
Stu.prototype=new Student(‘name’,22);
但如果Stu的参数要作为Student的参数可以这么写:
function Stu(name,age){ Student.apply(this,arguments) } Stu.prorotype= new Student(‘name’,22);
这里把Stu原型指向Student所以Stu实例对象instanceof Stu和Student都为true。
这点其实在jQuery源码中也是这么声明jQuery函数的。因为jquery是new jquery()和jquery()都返回对象。代码如下
var aQuery = function(selector, context) { return new aQuery.prototype.init(); } aQuery.prototype = { init: function() { this.age = 18 return this; }, name: function() {}, age: 20 }
但返回的对象要有init构造函数以及name方法。那么就要加一句:
var aQuery = function(selector, context) { return new aQuery.prototype.init(); } aQuery.prototype = { init: function() { return this; }, name: function() { return this.age }, age: 20 } aQuery.prototype.init.prototype = aQuery.prototype; console.log(aQuery().name()) //20
- 函数绑定
就是在改变函数的this指向,传统的用法是call或者apply。Es5中可以用bind
- 柯里化
之前介绍过,这里不做过多介绍
- 定时器
使用setTimeout() 和setInterval()创建的定时器可以用于实现有趣且有用的功能,这里有个注意的点:定时器不是在规定的时间就会运行,而是在规定的时间将这个函数放入到异步队列中(包括单击事件的触发都会加入到这个队列中)当进程空闲下来才执行队列中的代码。
除了主JavaScript执行进程外,还有一个需要在进程下一次空闲时执行的代码队列,随着页面的在其生命周期中的推移,代码会按照执行顺序添加入队列,例如,当某个按钮被按下时,他的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里执行,当接收到某个ajax响应时,回调函数的代码会被添加到队列,在JavaScript中没有任何代码是立刻执行的,但一旦进程空闲则尽快执行。
定时器队列的工作方式是,当特定时间过去后将代码插入,注意,给队列添加代码并不意味着对它立刻执行,而只能表示它会尽快执行。设定一个150ms后执行的定时器不代表了150ms代码就立刻执行,它表示代码会在150ms后被加入到队列中,如果在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面上看上去好像代码就在精确指定的时间上执行。其他情况下,代码可能明显等待更长时间才执行。
- 重复的定时器
使用setInterval()创建的定时确保了定时器代码规则地插入队列,这个方式的问题在于定时器代码可能在代码再次被添加发哦队列之前还没完成执行,结果导致定时器代码连续运行好几次,而之间没有任何停顿,幸好,JavaScript引擎够聪明,能避免这个问题,仅当没有该定时器的任何其他代码示例时,才将定时器代码添加发到队列中。
这种循环有两个问题:
1、 某些时间间隔会被跳过
2、 多个定时器执行之间的间隔可能会比预期的小。
为了避免这个两个问题,可以使用链式setTime()调用。
setTimeout(function(){ setTimeout(arguments.callee,interval); })
这样可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。
- 数组分块
在数组循环处理复杂操作并且这段代码不影响后面的其他代码的单独存在,可以用定时器来推迟到进程空闲状态下在执行。避免js开始运行时间太长。逻辑写法和上面一样。
- 函数节流
有些函数或事件需要频繁调用执行的时候,为了优化性能,加入定时器在规定的时候内调用这个函数,那先把之前未执行的定时器取消,然后在重新设定定时器。这样函数的运行次数就少了很多。性能优化很多,vue的双向数据绑定,在数据驱动下,数据频繁改动导致频繁调用绑定视图函数,就是用函数节流的方式优化性能。
函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行,第一次调用函数,创建一个定时器,在指定时间间隔之后运行代码,当第二次调用该函数时,它会清除前一次的定时器并设置另一个,如果前一个定时器已经执行过了,这个操作就没有任何意义,基本形式是:
var processor={ timeoutId:null, performProcessing:function(){}, process:function(){ clearTimeout(this.timeoutId); this.timeoutId=setTimeout(function(){ that.performProcessing(); },100); } }
(二):自定义事件、拖放、添加自定义事件、离线应用和客户存储