JavaScript是一种极其灵活的语言,具有多种使用风格。
高级函数
函数是JavaScript中最有趣的部分之一。
本质上是十分简单和过程化的,但也可以是非常复杂和动态的。
此外,由于所有的函数都是对象,所以使用函数指针非常简单
。这些令JavaScript函数不仅有趣而且强大。
以下是几种在JavaScript中使用函数的高级方法
安全的类型检测
JavaScript内置的类型检测机制并非完全可靠。
事实上,发生错误否定及错误肯定的情况也不在少数。
比如说typeof操作符吧,由于它有一些无法预知的行为,经常会导致检测数据类型时得到不靠谱的结果。
Safari在对正则表达式应用typeof操作符时会返回"function",因此很难确定某个值到底是不是函数。
再比如,instanceof操作符在存在多个全局作用域(像一个页面包含多个框架)的情况下,也是问题多多。
在检测某个对象到底是原生对象还是开发人员自定义的对象的时候,也会有问题。出现这个问题的原因是浏览器开始原生支持JSON对象了。因为很多人一直在使用Douglas Crockford的JSON库,而该库定义了一个全局JSON对象。于是开发人员很难确定页面中的JSON对象到底是不是原生的。
解决上述问题的办法都一样。大家知道,在任何值上调用Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串。
每个类在内部都有一个[[Class]]属性,这个属性中就指定了上述字符串中的构造函数名。
作用域安全的构造函数
构造函数其实就是一个使用new操作符调用的函数。
当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例,
如下面的例子所示:
function Person(name, age, job){ this.name = name; this.age = age; this.job = job;}var person = new Person("Nicholas", 29, "Software Engineer");
ScopeSafeConstructorsExample01.htm
上面这个例子中,Person构造函数使用this对象给三个属性赋值:name、age和job。当和new操作符连用时,则会创建一个新的Person对象,同时会给它分配这些属性。问题出在当没有使用new操作符来调用该构造函数的情况上。由于该this对象是在运行时绑定的,所以直接调用Person(),this会映射到全局对象window上,导致错误对象属性的意外增加。
作用域安全的构造函数在进行任何更改前,首先确认this对象是正确类型的实例。如果不是,那么会创建新的实例并返回。、
关于作用域安全的构造函数。实现这个模式后,你就锁定了可以调用构造函数的环境。如果你使用构造函数窃取模式的继承且不使用原型链,那么这个继承很可能被破坏。
多个程序员在同一个页面上写JavaScript代码的环境中,作用域安全构造函数就很有用了。届时,对全局对象意外的更改可能会导致一些常常难以追踪的错误。除非你单纯基于构造函数窃取来实现继承,推荐作用域安全的构造函数作为最佳实践。
惰性载入函数
因为浏览器之间行为的差异,多数JavaScript代码包含了大量的if语句,将执行引导到正确的代码中。
惰性载入表示函数执行的分支仅会发生一次。
有两种实现惰性载入的方式
第一种就是在函数被调用时再处理函数。在第一次调用的过程中,该函数会被覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支了。
第二种实现惰性载入的方式是在声明函数时就指定适当的函数。这样,第一次调用函数时就不会损失性能了,而在代码首次加载时会损失一点性能。
惰性载入函数的优点是只在执行分支代码时牺牲一点儿性能。至于哪种方式更合适,就要看你的具体需求而定了。不过这两种方式都能避免执行不必要的代码。
函数绑定
另一个日益流行的高级技巧叫做函数绑定。函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。
该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同时保留代码执行环境。
只要是将某个函数指针以值的形式进行传递,同时该函数必须在特定环境中执行,被绑定函数的效用就突显出来了。
它们主要用于事件处理程序以及setTimeout()和setInterval()。然而,被绑定函数与普通函数相比有更多的开销,它们需要更多内存,同时也因为多重函数调用稍微慢一点,所以最好只在必要时使用。
函数柯里化
与函数绑定紧密相关的主题是函数柯里化(function currying),它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。
柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。
curry()函数的主要工作就是将被返回函数的参数进行排序。curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。为了获取第一个参数之后的所有参数,在arguments对象上调用了slice()方法,并传入参数1表示被返回的数组包含从第二个参数开始的所有参数。然后args数组包含了来自外部函数的参数。在内部函数中,创建了innerArgs数组用来存放所有传入的参数(又一次用到了slice())。有了存放来自外部函数和内部函数的参数数组后,就可以使用concat()方法将它们组合为finalArgs,然后使用apply()将结果传递给该函数。注意这个函数并没有考虑到执行环境,所以调用apply()时第一个参数是null。
函数柯里化还常常作为函数绑定的一部分包含在其中,构造出更为复杂的bind()函数。
JavaScript中的柯里化函数和绑定函数提供了强大的动态函数创建功能。使用bind()还是curry()要根据是否需要object对象响应来决定。
它们都能用于创建复杂的算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销。
感谢大家支持,评论或者私我免费白嫖资源