读书笔记: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",28);
alert(person1.name);  //jame
alert(person1.age);   //28
alert(window.name)    //‘‘
alert(window.age)     //undefined

ps:实现这个模式后,同时就锁定了可以调用构造函数的环境,如果你使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏,如下:

 1 function Polygon(sides){
 2    if(this instanceof Polygon){
 3       this.sides=sides;
 4       this.getArea=function(){
 5          return 0;
 6       }
 7    }else{
 8        return new Polygon(sides);
 9    }
10 }
11 function rect(w,h){
12   Polygon.call(this,2);
13   this.width=w;
14   this.height=h;
15   this.getArea=function(){
16     return this.width*this.height
17   }
18 }
19 var rect1=new rect(5,10)
20 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 0;
      }
   }else{
       return new Polygon(sides);
   }
}
function rect(w,h){
  Polygon.call(this,2);
  this.width=w;
  this.height=h;
  this.getArea=function(){
    return this.width*this.height
  }
}
rect.prototype=new Polygon()
var rect1=new rect(5,10)
alert(rect.sides)  //2

注意代码中加粗的部分,这样一个rect实例同时也是一个Polygon实例,所以Polygon。call会按预定执行。

三。函数绑定

函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。该技巧常常和回调函数与事件处理程序一起使用,以便在将函数座位变量传递的同时保留代码执行环境,请看下面例子:

 1 var handler={
 2      message:"hello world",
 3      handleClick:function(event){
 4         alert(this.message)
 5      }
 6  }
 7  var btn=document.getElementById("my_btn");
 8  EventUtil.addHandler(btn,"click",handler.handleClick)//跨浏览器事件处理
 9  var EventUtil={
10      addHandler:function(element,type,handler){
11        if(element.addEventListener){
12            element.addEventListener(type,handler,false)
13        }else if(element.attachEvent){
14            element.attachEvent("on"+type,handler)
15        }else {
16           element["on"+type]=handler
17        }
18      },
19      removeHandler:function(element,type,handler){
20        if(element.removeEventListener){
21            element.removeEventListener(type,handler,false)
22        }else if(element.detachEvent){
23            element.detachEvent("on"+type,handler)
24        }else {
25           element["on"+type]=null
26        }
27      },
28  }

在这个例子中,我们对按钮绑定点击事件,当点击发生时,我们期望得到的是”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))

今天就到这里,接下来会研究 惰性载入函数及神秘的函数柯里化。

时间: 2024-10-14 04:08:28

读书笔记:javascript高级技巧(一)的相关文章

JavaScript语言精粹读书笔记- JavaScript对象

JavaScript 对象 除了数字.字符串.布尔值.null.undefined(都不可变)这5种简单类型,其他都是对象. JavaScript中的对象是可变的键控集合(keyed collections). 对象是属性的容器,其中每个属性都拥有名字和值. JavaScript中的对象是无类别的(class-free)的.它对新属性的名字和值没有约束. JavaScript包括一个原型链特性,允许对象继承另一对象的属性. 对象的检索: stooge[“first-name”]或者stooge.

读书笔记----JavaScript 权威指南(一)

0.前言 最近小编我刚刚结束上一段的工作,结果立马就马不停蹄的开始了新一轮的工作了,表示无辜,(o′?ェ?`o),程序猿真是个累死人不偿命的工作呀. 今天晚上看到同事新启封的 JavaScript 权威指南,心血来潮的想,如果我能把这个书里面的重点以及具体知识点梳理出来,那么后来的人是不是就能少走一些弯路呢? 抱着这个想法,于是就开始了今天晚上的读书之旅,更由于小编喜欢整理东西这个习惯,才有了此文. 真心希望看到这篇文章的你,能够感受到小编那深沉的爱!~ 1.JavaScript 语法核心 之

读书笔记——javascript变量作用域

<JavaScript权威指南>第6版第三章第10节: 一个变量的作用域(scope)是程序源代码中定义这个变量的区域.全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的.然而在函数内声明的变量只在函数体内有定义.它们是局部变量,作用域也是局部的.函数参数也是局部变量,它们只在函数体内有定义.   在函数体内,局部变量的优先级高于同名的全局变量.如果在函数内声明的一个局部变量或函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所遮盖. var scope = 

读书笔记-JavaScript中的全局对象

对于任何JavaScript程序,当程序开始运行时,JavaScript解释器都会初始化一个全局对象以供程序使用.这个JavaScript自身提供的全局对象的功能包括: 1.全局对象拥有一些常用的属性值.比如undefined.Infinity以及NaN.2.全局对象拥有一些常用的属性对象.比如Math.JSON和Number对象均为该全局对象的属性.3.全局对象提供一些全局函数供调用.比如isNaN().isFinite().parseInt()和eval()等.4.全局对象提供一些全局构造器

JavaScript语言精粹读书笔记 - JavaScript函数

JavaScript是披着C族语言外衣的LISP,除了词法上与C族语言相似以外,其他几乎没有相似之处. JavaScript 函数: 函数包含一组语句,他们是JavaScript的基础模块单元,用于代码复用.信息隐藏和组合调用. 函数用于指定对象的行为. 函数对象Functions: 在JavaScript中函数就是对象.对象是"键值"对的集合并拥有一个连接到原型对象的隐藏连接. 对象字面量产生的对象连接到Object.prototype.函数对象连接到Function.prototy

读书笔记 - javascript 高级程序设计 - 第二章 在Html中使用JavaScript

1 <script>的6个属性 async  立即下载当前script标签的外部脚本 但不能影响别的 charset 没用了 defer  文档显示之后再执行脚本,只对外部脚本有效 language 没用了 src type 描述代码内容Mine类型 默认就是text/javascript 没什么用 2 在解释器对<script>元素内部的所有代码求值完毕以前 页面中的其余内容都不会被浏览器加载或显示 3 有两种script 嵌入式 外部引入式 在解析外部引入式的js文件时,页面的

网摘读书笔记----javascript语言精粹

原文链接:http://www.cnblogs.com/Cohlint/archive/2012/11/26/2788790.html 1.6种值会为假(==false),分别是false,null,undefined,' ',0,NaN 2.typeof有6种值,分别是'number','string','boolean','undefined','function','object';其中typeof(null),结果是'object' 3.number类型总是64位浮点数,两个整数相除也可

[读书笔记]JavaScript 闭包(Closures)

1. 什么是闭包? 参考MDN. 2. 闭包的使用示例 2.1 示例1 1 <div>1</div> 2 <div>2</div> 3 <div>3</div> 4 <script> 5 var nodes = document.getElementsByTagName('div'); 6 for (var i = 0, len = nodes.length; i < len; i++) { 7 /* 注意这里 */

[读书笔记] JavaScript设计模式: 单例模式

单例模式:保证一个类只有一个实例,并提供一个可以访问它的全局访问点. 一种简单.方便的写法就是用一个变量来标识当前类是否已经创建过对象,如果有,则返回已经创建好的对象,否则创建一个新对象,并将其返回. var Singleton = function(name) { this.name = name; this.instance = null; } Singleton.prototype.getName = function() { alert(this.name); } Singleton.g

《JavaScript权威指南》读书笔记——JavaScript核心

前言 这本由David Flanagan著作,并由淘宝前端团队译的<JavaScript权威指南>,也就是我们俗称的“犀牛书”,算是JS界公认的“圣经”了.本书较厚(有1004页),读起来颇费功夫,但作为JavaScript(下文简称:JS)相关从业者,我还是鼎力推荐,一定要读完这本经久不息,好评如潮的JS“圣经”(如果您有耐心的读完,觉得还不错的,博客最后附有购买本书的优惠券,可自行领取). 说完本书重要性,下面重点介绍一下本书作者写书的逻辑性,简单来说本书分为四部分,第一部分:JS核心:第