1.类型检测

typeof有时返回值不合理,比如RegExp对象返回object,测试代码:

var regex = /^what$/i;
regex = new RegExp('^what$');
alert(typeof regex);

instanceof在页面有多个frame时用不了,来自不同frame的对象instanceof返回false

可以用Object.prototype.toString.call(value) === ‘[object Array/Function...]’来做类型检查,也可以用来区分原生对象和自定义对象,例如:

[object JSON]//原生JSON对象
[object Object]//自定义JSON对象

注意:IE中以COM对象形式实现的函数对象toString不会返回[object Function]

2.作用域安全的构造函数

用new操作符调用构造函数会给新创建的对象添加属性,而直接调用构造函数会给全局对象window添加属性

为了避免污染全局作用域,可以用如下构造函数:

/* 可能会污染全局作用域
function Student(name){
this.name = name;
}
*/
//作用域安全的构造函数
function Student(name){
if(this instanceof Student){
this.name = name;
}
else{
return new Student(name);
}
}

上面的构造函数能够避免直接调用构造函数给全局对象意外添加属性,但用这种方式实现继承可能会出现问题,类型检查可能导致继承失败

3.惰性载入(避免重复分支检测)

  1. 在第一次执行分支检测时,覆盖原有函数,例如:

    function detect(){
    if(...){
    detect = function(){
    //
    }
    }
    else if(...){
    detect = function(){
    //
    }
    }
    else...
    }
  2. 可以用匿名函数立即执行并返回匿名函数来实现惰性载入,例如:

    var detect = (function(){
    if(...){
    return function(){
    //
    }
    }
    else if(...){
    return function(){
    //
    }
    }
    else...
    })();

第一种方式第一次调用时损失性能,以后调用不会损失性能;第二种方式在第一次调用时也不会损失性能,因为把时耗放到了第一次载入代码时

4.函数绑定(指定执行环境)

可以用下面的函数给函数指定执行环境并创造新函数:

function bind(fun, context){
return function(){
return fun.apply(context, arguments);
}
}

可以方便地根据已有函数生成新函数,[IE9+]有原生的bind方法,例如var newFun = fun.bind(obj);

注意:函数绑定存在内存消耗多,执行慢的缺点

5.函数柯里化(也叫函数套用,允许指定一些参数)

创建柯里化函数的通用方式:

function curry(fun){
var args = Array.prototype.slice.call(arguments, 1);//去掉第一个参数fun,得到给定的参数值
return function(){
var innerArgs = Array.prototype.slice.call(arguments);//把内部arguments对象转换为数组(为了用concat方法)
var finalArgs = args.concat(innerArgs);//拼接参数列表
return fun.apply(null, finalArgs);//把拼接的参数列表传给fun
}
}

或者增强bind方法实现柯里化:

function bind(fun, context){
var args = Array.prototype.slice.call(arguments, 2);//去掉前2个参数
return function(){
var innerArgs = Array.prototype.slice.call(arguments);//同curry
var finalArgs = args.concat(innerArgs);//同curry
return fun.apply(context, finalArgs);//指定执行环境和参数
}
}

注意:柯里化和bind都存在额外开销,不要滥用

6.防篡改对象

  1. 不可扩展对象(不能添加新属性)

    var obj = {a : 1, b : 2};
    alert(Object.isExtensible(obj));//true
    Object.preventExtensions(obj);//把obj设置为不可扩展
    alert(Object.isExtensible(obj));//false
    obj.c = 3;
    alert(obj.c);//undefined

    注意:设置不可扩展操作无法撤销(改不回来),设置之后无法添加新属性,但可以修改/删除原有属性

  2. 密封对象(只能修改现有属性,无法删除或添加)

    var obj = {a : 1, b : 2};
    Object.seal(obj);//设置密封对象
    alert(Object.isSealed(obj));//true
    obj.c = 3;
    alert(obj.c);//undefined
    delete obj.a;//严格模式下报错
    alert(obj.a);//1
  3. 冻结对象(只读,访问器属性可写)

    var obj = {a : 1, b : 2};
    Object.freeze(obj);//设置密封对象
    alert(Object.isFrozen(obj));//true
    obj.a = 3;
    alert(obj.a);//1

上面的实现都是ES5新增的部分,浏览器支持性未知,本机测试[IE8-]不支持,Chrome和FF支持

7.函数节流

把耗时的大任务分割成小块,用setTimeout控制执行

优点:提高了页面响应速度

缺点:逻辑连贯性没了,实现难度增大,而且不易实现事务控制,因为完整事务被拆开了

8.观察者模式

用自定义事件可以实现观察者模式:

function EventTarget(){
this.handlers = {};
} EventTarget.prototype = {
constructor: EventTarget, addHandler: function(type, handler){
if (typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
} this.handlers[type].push(handler);
}, fire: function(event){
if (!event.target){
event.target = this;
}
if (this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for (var i=0, len=handlers.length; i < len; i++){
handlers[i](event);
}
}
}, removeHandler: function(type, handler){
if (this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for (var i=0, len=handlers.length; i < len; i++){
if (handlers[i] === handler){
break;
}
} handlers.splice(i, 1);
}
}
};

用法如下:

function handleMessage(event){
alert("Message received: " + event.message);
}
//创建新对象
var target = new EventTarget();
//添加事件处理器
target.addHandler("message", handleMessage);
//触发事件
target.fire({ type: "message", message: "Hello world!"});
//删除事件处理器
target.removeHandler("message", handleMessage);
//再次触发事件,应该没有事件处理器
target.fire({ type: "message", message: "Hello world!"});

JS学习笔记11_高级技巧的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. Vue.js学习笔记(2)vue-router

    vue中vue-router的使用:

  3. JS 学习笔记--9---变量-作用域-内存相关

    JS 中变量和其它语言中变量最大的区别就是,JS 是松散型语言,决定了它只是在某一个特定时间保存某一特定的值的一个名字而已.由于在定义变量的时候不需要显示规定必须保存某种类型的值,故变量的值以及保存的 ...

  4. WebGL three.js学习笔记 使用粒子系统模拟时空隧道(虫洞)

    WebGL three.js学习笔记 使用粒子系统模拟时空隧道 本例的运行结果如图: 时空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/demo/sprite ...

  5. WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法

    WebGL学习----Three.js学习笔记(5) 点击查看demo演示 Demo地址:https://nsytsqdtn.github.io/demo/360/360 简单网格材质 MeshNor ...

  6. WebGL three.js学习笔记 创建three.js代码的基本框架

    WebGL学习----Three.js学习笔记(1) webgl介绍 WebGL是一种3D绘图协议,它把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的 ...

  7. vue.js 学习笔记3——TypeScript

    目录 vue.js 学习笔记3--TypeScript 工具 基础类型 数组 元组 枚举 字面量 接口 类类型 类类型要素 函数 函数参数 this对象和类型 重载 迭代器 Symbol.iterat ...

  8. 2019-4-29 js学习笔记

    js学习笔记一:js数据类型   1:基本数据类型       number类型(整数,小数)      String类型          boolean类型        NaN类型其实是一个nu ...

  9. 一点感悟:《Node.js学习笔记》star数突破1000+

    写作背景 笔者前年开始撰写的<Node.js学习笔记> github star 数突破了1000,算是个里程碑吧. 从第一次提交(2016.11.03)到现在,1年半过去了.突然有些感慨, ...

随机推荐

  1. Spring项目解决Post乱码

    Java EE解决Post乱码:在web.xml中加入: <filter> <filter-name>encodingFilter</filter-name> &l ...

  2. System.ArgumentOutOfRangeException: 指定的参数已超出有效值的范围

    GridView指定的参数已超出有效值的范围GridView在更新过程中异常详细信息: System.ArgumentOutOfRangeException: 指定的参数已超出有效值的范围.参数名:v ...

  3. VC++ 如何在显示对话框的时候,指定焦点控件!

    很简单: 在你的CAddDlg类的OnInitDialog函数中加上你上面的代码GetDlgItem(IDC_EDIT1)->SetFocus();最后记得return FALSE; 其实,不知 ...

  4. DetailsView的添加,修改,删除,查询

    前台代码: <div> <asp:DetailsView ID="gvDepart" runat="server" AutoGenerateR ...

  5. MATLAB - 图像基本操作

    1.读入一幅图像 I = imread('lena.jpg');%给出图片路径即可,I是一个三维矩阵 J = rgb2gray(I); figure, imshow(I), figure, imsho ...

  6. vim--golang代码补全

    我想说,我折腾了很久编辑器,试了九种办法 最后我只成功了一种 但我依然想就我混乱的逻辑做下整理 一.一开始,我试图入手ipad编码软件,大概9美金吧,叫Textastic.我试图用它的近亲来试验Tex ...

  7. [jQuery]最新的 3.0 已发布

    可以从 https://code.jquery.com/jquery/#jquery-all-1.x 找到历史版本 1.12.4 是支持 IE6 - 8 的最高版本. 下载地址 http://file ...

  8. 新创建的项目利用git添加远程仓库

    git initgit remote add origin https:// //git账号中的网址 (git remote //可以查询添加的远程仓库) git add . //添加刚刚导入的整个工 ...

  9. 基于weka的文本分类实现

    weka介绍 参见 1)百度百科:http://baike.baidu.com/link?url=V9GKiFxiAoFkaUvPULJ7gK_xoEDnSfUNR1woed0YTmo20Wjo0wY ...

  10. rsyslog+mysql+loganalyzer搭建日志服务器<个人笔记>

    大概思路如下: 使用Linux自带的rsyslog服务来做底层,然后再使用mysql与rsyslog的模板来存储文件,并且以web来进行显示出来.<模板的存储以日期的树形结构来存储,并且以服务器 ...