读书笔记:javascript高级技巧(一)
一.安全的类型检测
javascript内置的类型检测机制并非完全可靠,由于浏览器或者作用域等原因,经常会发生错误。大家知道,在任何值调用toString()方法都会返回一个[object Native ConstructorName]格式的字符串,每个类内部都有一个[class]属性,这个属性就指定了上述字符串中的构造函数名。例如
var value=[1,2,3,4,5]
alert(Object.prototype.toString.call(value));//"[object Array]"
由此,我们可以创建函数来判断数据类型:
//示例
switch(Object.prototype.toString.call(value)){
case "[object Array]":
alert('array');
break;
case "[object Function]":
alert("function");
break;
case "[object RegExp]":
alert("regexp");
break;
case "[object JSON]":
alert("json")
break
}
二。作用域安全的构造函数:
我们来看下面的一个实例
function Person(name,age){
this.name=name;
this.age=age
}
//根据构造函数创建实例(正常情况应该是这样:var person=new Person("jame",29))
var person=Person("jame",29)
alert(person.name) //js报错,未定义
alert(person.age) //js报错,未定义
alert(window.name) //jame
由上可见,当我们没有使用new操作符调用构造函数Person时,this会映射到对象window上。这是由于this对象的晚绑定造成的,this对象是在运行时绑定的,所以直接调用Person(),构造函数座位普通函数调用,导致错误的发生。而且由于window的name属性是识别链接目标和frame的,所以这里对该属性的偶然覆盖可能会导致该页面上出现其他错误。这个问题的解决办法就是创建一个作用域安全的构造函数。如下:
function Person(name,age){
if(this instanceof Person){ //检测this对象是否为正确类型的实例,如若不是,那么创建新的对象并返回
this.name=name;
this.age=age;
}else{
return new Person(name,age)
}
}
var person1=new Person("jame",);
alert(person1.name); //jame
alert(person1.age); //
alert(window.name) //''
alert(window.age) //undefined
ps:实现这个模式后,同时就锁定了可以调用构造函数的环境,如果你使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏,如下:
function Polygon(sides){
if(this instanceof Polygon){
this.sides=sides;
this.getArea=function(){
return ;
}
}else{
return new Polygon(sides);
}
}
function rect(w,h){
Polygon.call(this,);
this.width=w;
this.height=h;
this.getArea=function(){
return this.width*this.height
}
}
var rect1=new rect(,)
alert(rect.sides) //undefined
按照以往理解,rect.sides的结果应为2.因为我们在rect函数的第一行用call方法调用了polygon的方法,可是结果为什么为undefined呢?
在这段代码中,Polygon构造函数的作用域是安全的,然而rect构造函数却不是。新创建一个rect实例后,这个实例应该通过Polygon。call来继承Polygon的sides属性。但是由于plygon函数的作用域是安全的,this对象并非polygon的实例,所以会创建并返回一个新的polygon对象。rect中的this并没有得到变化,同时polygon.call返回的值也没有用刀,所以rect实例中不会有sides属性。
解决办法如下:
function Polygon(sides){
if(this instanceof Polygon){
this.sides=sides;
this.getArea=function(){
return ;
}
}else{
return new Polygon(sides);
}
}
function rect(w,h){
Polygon.call(this,);
this.width=w;
this.height=h;
this.getArea=function(){
return this.width*this.height
}
}
rect.prototype=new Polygon()
var rect1=new rect(,)
alert(rect.sides) //
注意代码中加粗的部分,这样一个rect实例同时也是一个Polygon实例,所以Polygon。call会按预定执行。
三。函数绑定
函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用,以便在将函数座位变量传递的同时保留代码执行环境,请看下面例子:
var handler={
message:"hello world",
handleClick:function(event){
alert(this.message)
}
}
var btn=document.getElementById("my_btn");
EventUtil.addHandler(btn,"click",handler.handleClick)//跨浏览器事件处理
var EventUtil={
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false)
}else if(element.attachEvent){
element.attachEvent("on"+type,handler)
}else {
element["on"+type]=handler
}
},
removeHandler:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false)
}else if(element.detachEvent){
element.detachEvent("on"+type,handler)
}else {
element["on"+type]=null
}
},
}
在这个例子中,我们对按钮绑定点击事件,当点击发生时,我们期望得到的是”hello world“,可是结果却为undefiend。这个问题在于没有保存handler.handleClick的环境,所以this对象指向Dom按钮而非handler,我们可以用闭包来修正此问题;如下:
var handler={
message:"hello world",
handleClick:function(event){
alert(this.message)
}
}
var btn=document.getElementById("my_btn");
EventUtil.addHandler(btn,"click",function(event){
handler.handleClick(event);
})
这个解决方案在事件处理程序内使用了一个闭包直接调用handler.handleClick()。当然床架你多个闭包可能使代码变得难于理解和调试,因此很多javascript库实现了一个可以函数绑定到制定环境的函数,一般叫bind();一个简单的bind函数接手一个函数和环境,并返回一个在给定环境中调用给定函数的函数,并将所有参数是原封不动传递过去。语法如下:
function bind(fn,context){
return function(){
return fn.apply(context,arguments)
}
}
在bind中创建了闭包,闭包使用apply()调用传入的函数,并给apply()传递context对象和参数(参数是内部函数的并非bind()的)。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。在ECMAScript 5中为所有函数定义了一个月uansheng的bind()方法,与上面bind()方法类似,都是要传入作为this值得对象。支持原生bind()方法的浏览器有IE9+,Firefox 4+,Chrome。只要是将某个函数指针以值得形式进行传递,同时该函数必须在特定环境中执行,被绑定函数的效用就凸显歘来了。然后被绑定函数与普通函数相比有更多的开销,他们需要更多内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用。
原生调用方法如下:
var handler={
message:"hello world",
handleClick:function(event){
alert(this.message+":"+event.type)
}
}
var btn=document.getElementById("my_btn");
EventUtil.addHandler(btn,"click",handler.handleClick.bind(handler))
今天就到这里,接下来会研究 惰性载入函数及神秘的函数柯里化。
读书笔记:javascript高级技巧(一)的更多相关文章
- [读书笔记]javascript语言精粹'
人比较笨,以前只做项目,案例,然而一些javascript的很多理论不知道该怎么描述,所以最近开启一波读书之旅: 标识符 1.定义 标识符以字母开头,可能后面跟上一个或多个字母.数字或者下划线. 2. ...
- 读书笔记-----javascript基本数据类型
由于js基础差, 记性也不好,准备一边读书一边做记录,希望这样能加深一下记忆 /* 第一天 */ javascript 基本数据类型 js一共只有五种数据类型 Undefined, Nu ...
- 读书笔记-JavaScript面向对象编程(一)
PDF下载链接: http://pan.baidu.com/s/1eSDSTVW 密码: 75jr 第1章 引言 1.1 回顾历史 1.2 变革之风 1.3 分析现状 1.4 展望未来 1.5 面向对 ...
- JavaScript语言精粹读书笔记 - JavaScript函数
JavaScript是披着C族语言外衣的LISP,除了词法上与C族语言相似以外,其他几乎没有相似之处. JavaScript 函数: 函数包含一组语句,他们是JavaScript的基础模块单元,用于代 ...
- 读书笔记-JavaScript中的全局对象
对于任何JavaScript程序,当程序开始运行时,JavaScript解释器都会初始化一个全局对象以供程序使用.这个JavaScript自身提供的全局对象的功能包括: 1.全局对象拥有一些常用的属性 ...
- 读书笔记-JavaScript面向对象编程(三)
第7章 浏览器环境 7.1 在HTML页面中引入JavaScript代码 7.2概述BOM与DOM(页面以外事物对象和当前页面对象) 7.3 BOM 7.3.1 window对象再探(所以JavaSc ...
- 《JavaScript权威指南》读书笔记——JavaScript核心
前言 这本由David Flanagan著作,并由淘宝前端团队译的<JavaScript权威指南>,也就是我们俗称的“犀牛书”,算是JS界公认的“圣经”了.本书较厚(有1004页),读起来 ...
- 读书笔记-JavaScript高级程序设计(1)
1.组合继承 (JavaScript 中最常用的继承模式 ) (position: page168) (书中定义了两个变量名 SuperType SubType 乍一看 感觉不太能区分,我将改为 ...
- JavaScript语言精粹读书笔记- JavaScript对象
JavaScript 对象 除了数字.字符串.布尔值.null.undefined(都不可变)这5种简单类型,其他都是对象. JavaScript中的对象是可变的键控集合(keyed collecti ...
- [读书笔记]JavaScript 闭包(Closures)
1. 什么是闭包? 参考MDN. 2. 闭包的使用示例 2.1 示例1 <div>1</div> <div>2</div> <div>3&l ...
随机推荐
- MVC - 11(上).DTO
1.重要:javaScriptSerializer 无法识别被序列化的对象里各种属性是否存在 循环依赖 (System,Web.Script.Serialization.JavaScriptSeri ...
- Spring.Net的IOC入门
1.构造器注入 namespace Spring.Net { class Program { //构造器注入 static void Main(string[] args) { IApplicatio ...
- 【转载】 Python 方法参数 * 和 **
Python的函数定义中有两种特殊的情况,即出现*,**的形式. 如:def myfun1(username, *keys)或def myfun2(username, **keys)等. 他们与函数有 ...
- PHP保留小数位的三种方法
/** * PHP保留两位小数的几种方法 * @link http://www.phpddt.com */ $num = 10.4567; //第一种:利用round()对浮点数进行四舍五入 echo ...
- js或jquery实现页面打印可局部打印
方法一:直接用js的打印方法 <input id="btnPrint" type="button" value="打印" onclic ...
- Axure 全局辅助线(转)
普通辅助线作用于当前页 全局作用于所有页面 , 包括新建页面 创建普通辅助线直接拉出来 创建全局辅助线 , 在拉出来的时候按住 Ctrl 默认情况下 , 颜色不同 辅助线可以多选 , 用拖选 或 按 ...
- MySQL中的约束简单使用
数据库约束是为了保证数据的完整性而实现的一套机制,它具体的根据各个不同的数据库的实现而有不同的工具.一般来说有以下几种实现方式:1.检查约束:通过在定义数据库表里,在字段级或者是在表级加入的检查约束, ...
- 看懂UML类图与时序图
看懂UML类图和时序图 这里不会将UML的各种元素都提到,我只想讲讲类图中各个类之间的关系: 能看懂类图中各个类之间的线条.箭头代表什么意思后,也就足够应对 日常的工作和交流: 同时,我们应该能将类图 ...
- 【criteria CascadeType】级联的不同情况
使用criteria进行增删改查操作,可能会发生级联删除的情况,例如对员工表进行删除,可能会级联删除掉部门表中的某一条信息[类似这样的情况] 对此,我们可以在实体类中对级联的关系进行管理: 对于cri ...
- eclipse->project->clean…作用
其实主要作用就是把编译好的class等文件删除,激活eclipse的自动编译.解决的问题就是,有时候你把代码改了,但因为一些未知的原因,eclipse的自动编译没有成功,导致运行结果不正常.当你的工程 ...