第22章,高级技巧

高级函数

安全的类型检测

typeof会出现无法预知的行为
instanceof在多个全局作用域中并不能正确工作
调用Object原生的toString方法,会返回[Object NativeConstructorName]格式字符串。每个类内部都有一个[[Class]]属性,这个属性中就指定了上述字符串中的构造函数名。
原生数组的构造函数名与全局作用域无关,因此使用toString方法能保证返回一致的值,为此可以创建如下函数:
function isArray(value){return Object.prototype.toString.call(value) == "[object Array]";
}

也可以基于这一思路测试某个值是不是原生函数或正则表达式:

//判断是否原生函数
function isFunction(value){return Object.prototype.toString.call(value) == "[object Function]";
}
//判断是否原生函数
function isFunction(value){return Object.prototype.toString.call(value) == "[object RegExp]";
}

注:对于IE中以COM对象形式实现的任何函数,isFunction都将返回false,因为他们并不是js原生函数
注:Object的toString方法不能检测非原生构造函数的函数名。

作用域安全的构造函数

对于构造函数,使用了new操作符,则首先创建一个新的对象,将this指针指向新创建的对象,如果没有使用new操作符,则this指针会指向window对象,作用域安全的构造函数:

function Person(name,age,job){if(this instanceof Person){          //判断this是否是正确的类型this.name = name;this.age = age;this.job = job;}else{return new Person(name,age,job);}
}var per1 = Person("Nicholas",29,"Software Engineer");
alert(window.name);         //""
alert(per1.name);           //"Nicholas"var per2 = new Person("Shelby",34,"Ergonomist");
alert(per2.name);           //"Shelby"

建议:推荐使用作用域安全的构造函数作为最佳实践

惰性载入函数

对于多分支的if语句,有些时候并不需要每次都查询if语句,例如createXHR函数:

function createXHR(){if(typeof XMLHttpRequest != "undefined"){return new XMLHttpRequest;}else if(typeof ActiveXObject != "undefined"){if(typeof arguments.callee.activeXString != "string"){var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;for(i=0,len=versions.length;i < len;i++){try{new ActiveXObject(versions[i]);arguments.callee.activeXString = versions[i];break;}catch(ex){//跳过
                }}}return new ActiveXObject(arguments.callee.activeXString);}else{throw new Error("No XHR Object available");}
}

需要每次都对浏览器进行检测,根本没有必要,只要检测一次就足够了。对于此情况,解决方案:惰性载入技巧
惰性载入表示函数分支只会执行一次。
方法1、在函数被调用时处理函数,在第一次调用时该函数会被覆盖为另一个按合适方式执行的函数。

function createXHR(){if(typeof XMLHttpRequest != "undefined"){createXHR = function(){                             //将原函数覆盖return new XMLHttpRequest();};}else if(typeof ActiveXObject != "undefined"){createXHR = function(){                             //将原函数覆盖if(typeof arguments.callee.activeXString != "string"){var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;for(i=0,len=versions.length;i < len;i++){try{new ActiveXObject(versions[i]);arguments.callee.activeXString = versions[i];break;}catch(ex){//跳过
                    }}}return new ActiveXObject(arguments.callee.activeXString);};}else{createXHR = function(){                           //将原函数覆盖throw new Error("No XHR object available.");};}return createXHR();
}

方法2、在声明函数时指定适当的函数,这样第一次调用函数不损失性能,在代码首次加载时会损失性能

var createXHR = (function(){if(typeof XMLHttpRequest != "undefined"){return function(){return new XMLHttpRequest();};}else if(typeof ActiveXObject != "undefined"){return function(){if(typeof arguments.callee.activeXString != "string"){var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;for(i=0,len=versions.length;i < len;i++){try{new ActiveXObject(versions[i]);arguments.callee.activeXString = versions[i];break;}catch(ex){//跳过
                    }}}return new ActiveXObject(arguments.callee.activeXString);};}else{return function(){throw new Error("No XHR object available.");};}
})();

函数绑定

函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用。

var handler = {message : "Event handled",handleClick : function(event){alert(this.message);}
};var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn,"click",handler.handleClick);      //按钮按下显示undefined,不显示Event handled

按下按钮实际显示的是undefined,并不会显示Event handled。问题在于没有保存handler.handleClick的环境,所以this最后指向了DOM按钮,而非handler(IE8中this指向window),可以使用闭包解决问题:

var handler = {message : "Event handled",handleClick : function(event){alert(this.message);}
};var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn,"click",function(event){handler.handleClick(event);                                             //按钮按下显示Event handled
});

问题:闭包难以理解和调试。
大部分js库为此实现了可以将函数绑定到指定环境的函数,一般叫做bind()
简单的bind函数,接收一个函数和环境,返回一个给定函数中调用给定函数的函数,并且将所有参数原封不动传过去

//bind函数解决方案
function bind(fn,context){return function(){return fn.apply(context,arguments);};
}

调用方法:

EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler));
ECMAScript5为所有函数定义了原生的bind函数,进一步简化了操作。调用方法
EventUtil.addHandler(btn,"click",handler.handleClick.bind(handler));          //传入作为this的对象

支持的浏览器:IE9+,Firefox4+,Chrome

函数柯里化

用于创建已经设置好了一个或多个参数的函数。基本方法和函数绑定一样:使用闭包返回一个函数。区别:函数被调用时返回的函数还需要设置一些传入参数。

防篡改对象

注意:一旦把对象定义为防篡改对象,将不可撤销,跟定义了属性的[[Configurable]]为false的结果差不多

不可扩展对象

使用Object.preventExtensions()方法,让你不能再给对象添加属性和方法

var person = { name : "name"};
Object.preventExtensions(person);person.age = 28;
alert(person.age);          //undefined
Object.isExtensible可检测对象是否可扩展

密封对象

密封对象不可扩展,而且已有成员的[[Configurable]]特性将被设置为false。意味着不能修改或删除属性和方法
使用Object.seal()方法密封对象,使用Object.isSealed()方法确定对象是否密封。

var person = { name : "name" };
alert(Object.isExtensible(person));             //true
alert(Object.isSealed(person));                 //false

Object.seal(person);
alert(Object.isExtensible(person));             //false
alert(Object.isSealed(person));                 //true

冻结对象

最严格防篡改级别。冻结对象既不可扩展,又是密封,对象的数据属性的[[Writable]]特性会被设置为false。如果定义了[[Set]]函数,访问器属性仍然可写。
使用Object.freeze()方法冻结对象,Object.isFrozen()方法检测对象是否冻结。

高级定时器

js是单线程的,定时器仅仅只是计划代码在未来某个时间执行,执行时间并不确定。意思就是,js是单线程的,所有需要处理的代码都要排到执行队列中去,而定时器,只是在我们设定的时间之后将代码添加到队列中去,并不一定马上执行代码。

重复定时器

setInterval定时器的功能缺陷:可能在代码再次被添加到队列中时,之前的代码还没有完成执行,结果导致代码运行好几次。js引擎足够聪明,能避免这个问题,在使用setInterval时,仅当没有定时器的任何其他代码实例时,才将定时器代码加入到队列。不过,还是有问题,1、某些间隔会被跳过,多个定时器的代码执行之间的间隔可能比预期小。

使用setTimeout方法(超时调用,执行一次后再定义一个,模拟循环)来定义重复定时器可以避免这些缺点。

函数节流

函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定时间间隔之后运行代码。当第二次调用函数时,会清除前一次的定时器并设置另一个,如果前一个已经执行过了,此操作无意义。然而,若前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的在于只有执行函数的请求停止了一段时间后才执行。

自定义事件

拖放

第24章,最佳实践

可维护性

特性:

1、可理解
2、直观
3、可适应
4、可扩展
5、可调试

代码约定

1、可读性
(1)使用若干空格而非制表符进行缩进
(2)注释
函数和方法:每个函数或方法都应该包含一个注释,用于描述目的和用于完成任务所可能使用的算法,参数意义,返回值
大段代码:描述任务的注释
复杂算法:解释如何做的注释
Hack:因浏览器差异,js代码通常会包含一些hack,这些需要注释。
2、变量和函数命名
(1)变量名应为名词
(2)函数名应以动词开头,getName(),返回布尔值的函数以is开头,isEnable()
(3)使用合乎逻辑的名字,不必担心长度,长度问题可以使用后处理和压缩。
3、变量类型透明
很容易忘记变量所应包含的数据类型。合适的命名方式可以一定程度上缓解问题。还有以下三种表示变量数据类型的方式。
(1)变量初始化
(2)使用匈牙利标记法来指定变量类型。即,在变量前加一个或多个字符表示变量类型。
(3)使用变量注释

var found /*Boolean*/ = false;

松散耦合

1、解耦HTML/JavaScript
理想情况:HTML和JavaScript应完全分离,使用外部文件和DOM附加行为来包含JavaScript
2、解耦CSS/JavaScript

//CSS对于JavaScript的紧密耦合
element.style.color = "red";
element.style.backgroundColor = "blue";//CSS对于JavaScript的松散耦合
elements.className = "edit";

3、解耦应用逻辑/事件处理程序

编程实践

1、尊重对象所有权

意思是,不能修改不属于自己的对象。就是说,不是自己创建或维护的对象,就不要更改它的属性和方法,即
(1)不要为实例或原型添加属性
(2)不要为实例或原型添加方法
(3)不要重定义已存在的方法

2、避免全局变量

最多创建一个全局变量

3、避免与null进行比较

4、使用常量

var Constants = {INVALID_VALUE_MSG:"Invalid value!",INVALID_VALUE_URL:"/errors/invalid.php"
};function validate(value){if(!value){alert(Constants.INVALID_VALUE_MSG);location.href = Constants.INVALID_VALUE_URL;}
}

性能

注意作用域

1、避免全局查找
2、避免with语句

选择正确方法

1、避免不必要的属性查找
2、优化循环
(1)减值迭代在大多数情况下更高效,即循环从最大值开始
(2)简化终止条件
(3)简化循环体
(4)使用后测试循环,do-while循环
3、展开循环
当循环次数是确定的,消除循环并使用多次函数调用往往会更快。
Duff装置。
4、避免双重解释

最小化语句

1、多变量声明

//4个语句---浪费
var count = 5;
var color = "red";
var values = [1,2,3];
var now = new Date();//一个语句
var count = 5;color = "red";values = [1,2,3];now = new Date();

2、插入迭代值

var name = values[i];
i++;
//合并
var name = values[i++];

3、使用数组和对象字面量

优化DOM操作

1、最小化现场更新(使用仓库)
可以使用DocumentFragment,一次插入多项更改
2、使用innerHTML
对于大的DOM更改,innerHTML方法,比使用标准的DOM方法(createElements,appendChild之类)速度快的多。
3、使用事件代理
4、注意HTMLCollection

压缩

代码长度和配重

代码长度:浏览器所需解析字节数
配重:实际从服务器传送到浏览器的字节数
1、文件压缩(使用压缩工具)
删除额外空白
删除所有注释
缩短变量名
2、HTTP压缩

第25章,新兴API

requestAnimationFrame()

与动画相关

Page VisibilityAPI

因不知道用户是否正在与页面交互而推出的,能够让开发人员知道页面是否对用户可见

Geolocation API

地理定位,navigator.geolocation对象。

File API

宗旨:为Web开发人员提供一种安全的方式,以便在客户端访问用户计算机中的文件

FileReader类型

实现的是一种异步文件读取机制,方法:
readAsText(file,encoding):以纯文本形式读取文件,保存到result属性中,第二个参数可选
readAsDataURL(file):读取文件并将文件以数据URI的形式保存到result属性
readAsBinaryString(file):读文件并将一个字符保存在result属性,字符串中每个字符表示一字节
readAsArrayBuffer(file):读文件并将一个包含文件内容的ArrayBuffer保存在result属性中

读取部分内容

File对象支持slice方法

对象URL

也被称为blob URL,指的是引用在File或Blob中的数据的URL

Web计时

Web Workers

转载于:https://www.cnblogs.com/TwinklingZ/p/5280970.html

JavaScript高级程序设计(第三版)学习笔记22、24、25章相关推荐

  1. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  2. JavaScript高级程序设计第四版学习--第二十四章

    title: JavaScript高级程序设计第四版学习–第二十四章 date: 2021-5-31 10:46:01 author: Xilong88 tags: JavaScript 本章内容: ...

  3. Js高级程序设计第三版学习(十二章)

                                  Js高级程序设计第三版学习(十二章) 第十二章 DOM2和DOM3   1.样式: 访问样式属性 任何支持style特性的HTML元素都有一 ...

  4. JavaScript高级程序设计红宝书学习笔记第三章基本概念

    第三章 基本概念 本章内容 语法 数据类型 操作符 语句 函数 3.1 语法 3.1.1 区分大小写,ECMAScript中的一切(变量.函数名和操作符)都区分大小写. 3.1.2 标识符 标识符:变 ...

  5. javascript 高级程序设计(第4版)阅读笔记(三)

    第3章,内容很长,所以更得慢,主要讲的是ECMAScript   es的语言基础:语法.数据类型.基本操作符.流控制语句.理解函数,ECMAScript 的语法很大程度上借鉴了 C 语言和其他类 C  ...

  6. javascript高级程序设计 第三版

    网盘地址 提取码:vh81 笔记 第二章 2.1script标签 <script>元素属性:async.charset.defer.language.src.type async和defe ...

  7. JavaScript高级程序设计第三版 第3章 基本概念

    第3章 基本概念 3.1 语法 3.1.1 区分大小写 3.1.2 标识符 3.1.3 注释 3.1.4 严格模式 3.1.5 语句 3.2 关键字和保留字 3.3 变量 3.4 数据类型 3.4.1 ...

  8. 阅读JavaScript高级程序设计(第二版)笔记

    第一章js简介 JavaScript诞生在1995年,当时负责进行输入型验证. JavaScript是一种专为与网页交互而设计的脚本语言,分为 : 1. ECMAScript核心语言功能. 2.文档对 ...

  9. 10.1.2 Document类型【JavaScript高级程序设计第三版】

    JavaScript 通过Document 类型表示文档.在浏览器中,document 对象是HTMLDocument(继承自Document 类型)的一个实例,表示整个HTML 页面.而且,docu ...

  10. 13.4.3 鼠标与滚轮事件【JavaScript高级程序设计第三版】

    鼠标事件是Web 开发中最常用的一类事件,毕竟鼠标还是最主要的定位设备.DOM3 级事件中定义了9 个鼠标事件,简介如下. click:在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发.这 ...

最新文章

  1. Android Tab大总结 Fragment+TabPageIndicator+ViewPager
  2. error CS0234: 命名空间“System.Drawing”中不存在类型或命名空间名称“Image”
  3. python3环境下用matplotlib库实现UI交互
  4. linux kvm安装win7,ubuntu14.04 使用kvm安装win7系统
  5. 推荐系统——GBDT+LR
  6. Python3 爬虫实战 — 模拟登陆哔哩哔哩【滑动验证码对抗】
  7. 记录通用权限管理系统组件使用心得体会,写技术博客赢IPad2
  8. 在C#中将字符串转换为字节数组
  9. php curl 命令行,curl 命令行教程
  10. 专利申请“技术交底书”的要素和撰写要求
  11. C语言中表示温度符号,摄氏度符号怎么打(SCI论文中摄氏度°C符号的正确输法)...
  12. 入职两个月的一些感受
  13. 数据结构---第四章:串
  14. 客户关系管理之会员管理
  15. java反射机制的优点和缺点
  16. 几种常见MOSFET栅极驱动电路
  17. inflate使用方法总结
  18. 别让自大成为职场绊脚石
  19. 腾云忆想构建云化IT生态,助力我国“双循环经济”数字化升级
  20. OLTP OLAP

热门文章

  1. 计算机应用入学考试,本科【计算机应用】入学考试模拟试题.doc
  2. eclipse服务器添加项目工程,eclipse创建和发布web项目(示例代码)
  3. 好看的二次元个人主页导航源码 动态背景+背景音乐
  4. 淘宝客API网站在这两年里经历了不少次百度K站风波
  5. Net Framework类库中提供的线程同步设施包括:
  6. GetWindowThreadProcessId
  7. CGI脚本跨站截取Cookie/附ASP的版本
  8. DotFuscator使用步骤
  9. Magento调试 - 页面空白,打开错误报告的方法
  10. 人工智障学习笔记——强化学习(5)DRL与DQN