第22章 高级技巧

22.1 高级函数

22.1.1 安全的类型检测

对于之前,我们要去判断一个变量的类型,对于基本类型的,可以使用typeof,对于引用类型的,我们可以使用 instanceof ,不过,这两种方法在某些情况下,是不可靠的,会存在一些兼容性问题。

接下来,我们介绍一种更佳可靠的检测方法:

我们知道,在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstrectorName] 格式的字符串,每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。

比如,我们可以使用下面方法来检测各种对象:

function isArray(value){
   return Object.prototype.toString.call(value) === "[object Array]";
}

function isFunction(value){
   return Object.prototype.toString.call(value) === "[object Function]";
}

function isRegExp(value){
   return Object.prototype.toString.call(value) === "[object RegExp]";
}

22.1.2 作用域安全的构造函数

构造函数其实就是一个使用 new 操作符调用的函数。当使用 new 调用时,构造函数内用到的this对象会指向新创建的对象实例。

我们来看一个使用构造函数的例子:

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
}

var person = new Person('jack', 29, 'teacher');

person.name ==> 'jack'
person.age ==> 29
person.job ==> 'teacher'

可是!!!
这个模式会出现一个问题,在你有意或者无意漏掉 new 操作符时,会发生以下事情

function Person(name, age, job){
  this.name = name;
  this.age = age;
  this.job = job;
}

var person = Person('jack', 29, 'teacher');

person.name ==> 报错

window.name ==> 'jack'
window.age ==> 29
window.job ==> 'teacher'

这是什么原因呢???

因为漏掉了 new 操作符后,Person()被作为普通函数调用,大家知道,普通函数内部的this指向了window,所以name,age,job
这三个属性会被挂载到window对象上,造成全局变量污染。

这一点,对于构造函数来说,是一个极大的问题,怎么样避免这个问题,可以更安全的使用自己的构造函数呢????

那就是:创建一个作用域安全的构造函数!!!!

function Person(myName, age, job){

  if( this instanceof Person ){
    this.myName = myName;
    this.age = age;
    this.job = job;
  } else {
    return new Person(myName, age, job);
  }
}

var person = Person('jack', 29, 'teacher');

window.myName ==> undefined
person.myName ==> 'jack'

22.1.3 惰性载入函数

22.1.4 函数绑定

22.1.5 函数柯里化

22.2 防篡改对象

22.2.1 不可扩展对象

默认情况下,所有对象都是可扩展的。

比如:

var person = { name: 'jack' };
person.age = 20;

如何禁止给对象添加扩展呢??可以使用对象的 Object.preventExtensions()方法

var person = { name: 'jack' };

Object.preventExtensions(person);

person.age = 20;

console.log(person.age) ==》 undefined

还有,使用 Object.isExtensible() 可以检测对象是否可扩展

22.2.2 密封的对象

可以使用 Object.seal() 方法使一个对象成为密封对象。成为密封对象后,此对象将不可扩展,而且其属性不可删除,但是可以修改

var person = { name: 'jack' };
Object.seal(person);


delete person.name;
alert(person.name);  ==> 'jack'

person.name = 'pony';
alert(person.name) ==> 'pony';

可以使用 Object.isSealed() 来检测对象是否被密封了。

22.2.3 冻结的对象

最严格的防篡改级别是冻结对象。冻结的对象,既不可扩展,又是密封,又不能修改其属性。

即 Object.freeze();

对于一个JS库而言,冻结对象是很有用的。因为可以极大的防止库中核心对象被修改。

22.3 高级定时器

定时器对队列的工作方式是:当特定事件过去后,将代码插入。注意,给队列添加代码并不意味着代码会立即执行,只能表示它会尽快执行。
等待浏览器线程空闲会执行。

使用 setInterval() 会存在以下问题:
(1) 某些间隔会被跳过
(2) 多个定时器的代码执行之间的间隔可能会比预期的小。

所以,推荐使用 setTimeout() 来代替 setInterval()

22.3.2 Yielding Processes

不同于桌面应用往往能够随意控制他们要的内存大小和处理器时间,JS被严格限制了,以防止恶意的web程序员把用户电脑搞挂了。

22.3.3 函数节流(重要概念)

在浏览器中,某些计算和处理要比其他的昂贵很多,其高频率的更改可能会让浏览器崩溃。为了绕开这个问题,你可以使用定时器对该函数进行节流。

函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。

该模式的基本形式:

var processor = {
  timeoutId: null,

  //实际进行处理的方法
  performProcessing: function(){
    //实际执行的代码
  },

  //初始处理调用的方法
  process: function(){
    clearTimeout( this.timeoutId );

    var that = this;
    this.timeoutId = setTimeout(function(){
      that.performProcessing();
    },100);
  }
}

//尝试开始执行
processor.process();

当调用了 process(),第一步是清除存好的 timeoutId,来阻止之前的调用被执行。然后创建一个新的定时器调用 performProcessing()。

可以将以上函数用下面这个函数来简化

function throttle(method, context){
   clearTimeout( method.tId );
   method.tId = setTimeout(function(){
       method.call(context)
   },100)
}

接下来,我们再来看一个例子:

window.onresize = function(){
  var div = document.getElementById('myDiv');
  div.style.height = div.offsetWidth + 'px';
}

不知道大家有没有意识到,上面这段代码可能会带来两个问题:

(1):首先,要计算 offsetWidth 属性,如果该元素或页面上其他元素有非常复杂的CSS样式,那么这个过程将会很复杂。
(2):其次,设置某个元素的高度需要对页面进行回流来令改动生效。如果页面有很多元素同时应用了相当数量的css,那么又会有很多计算。

节流优化后的代码:

function resizeDiv(){
  var div = document.getElementById('myDiv');
  div.style.height = div.offsetWidth + 'px';
}

window.onresize = function(){
    throttle(resizeDiv);
}

总结,只要代码是周期性执行的,都应该使用截流,比如以下js事件:input、scroll、resize等。

如果大家有人用过 underscore.js,里面有关于函数节流(throttle)与函数去抖(debounce)两个方法,大家可以比较学习下

我贴个别人的链接http://www.cnblogs.com/fsjohnhuang/p/4147810.html

你可能感兴趣的:(第22章 高级技巧)