第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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • 22.1
    虎嗅添香阅读 98评论 0 0
  • 前言 人生苦多,快来 Kotlin ,快速学习Kotlin! 什么是Kotlin? Kotlin 是种静态类型编程...
    任半生嚣狂阅读 26,139评论 9 118
  • 这个世界上最伟大的是光荣的胜利比光荣的胜利更伟大的是诚实的失败:诚实的失败证明我们曾经尝试过不可能的事。
    郭绿狮阅读 196评论 0 1
  • ♥ One ♥我记得,我上高中那会儿。我一姐们儿跟我一同班同学在一起了,俩人就天天腻在一块儿。那会儿我姐们要去另一...
    小小小儿郎阅读 658评论 0 0