作用域安全的构造函数
当使用构造函数时,如果没有使用new来调用,可能会导致this映射到全局对象window上,导致错误对象属性的意外增加。
而作用域安全的构造函数在进行任何更改千,首先确认this对象是否是正确类型的对象。如果不是,会创建新的实例并返回
1 2 3 4 5 6 7 8 9
| function Person(name,age,job){ if(this instanceof Person){ this.name = name; this.age = age; this.job = job; }else{ return new Person(name,age,job); } }
|
不过需要注意的是,这个模式锁定了可以调用构造函数的环境。如果使用构造函数窃取模式的继承且不适用原型链,那么这个继承很可能被破坏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function Polygon(sides){ if(this instanceof Polygon){ this.sides = sides; this.getArea = function(){ return 0; } }else{ return new Polygon(sides); } } function Rectangle(width,height){ Polygon.call(this,2); this.width = width; this.height = height; this.getArea = function(){ return this.width*this.height; } } Rectangle.prototype = new Polygon(); var rect = new Rectangle(5,10); alert(rect.sides)
|
惰性载入函数
惰性载入表示该函数执行的分支仅会发生一次:即函数第一次调用的时候。在第一次调用的过程中,该函数会被覆盖为另外一个按合适方式执行的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| var key = 0; function createVar(){ console.log('hello'); if(key == 1){ createVar = function(){ return 111; } }else if( key ==2 ){ createVar = function(){ return 222; } }else{ createVar = function(){ return 333; } } return createVar(); }
console.log(createVar()); console.log(createVar()); console.log(createVar()); console.log(createVar());
hello 333 333 333 333
|
两个主要优点:
- 要执行的适当代码只有当实际调用函数时才进行
- 尽管第一次调用该函数会因为额外的第二个函数调用而稍微慢一点,后续调用会更快
函数绑定
函数绑定要创建一个函数,可以在特定环境中以指定参数调用另一个函数。常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递时保留代码执行环境
使用闭包可能使代码变得难以理解和调试,可以使用bind函数
1 2 3 4 5
| function bind(fn,context){ return function(){ return fn.apply(context,arguments); } }
|
在bind中创建了一个闭包,闭包使用apply调用传入的函数,并传递context对象和参数
缺点:被绑定函数与普通函数相比有更多的开销——需要更多的内存,同时也因为多重调用稍微慢一点,最好只在必要时使用
函数柯里化
用于创建已经设置好了一个或多个参数的函数。基本方法和函数绑定是一样的:使用闭包返回一个函数。
两者的区别在于:当函数被调用时,返回的函数还需要设置一些传入的参数
1 2 3 4 5 6 7 8
| function add(num1,num2){ return num1+num2; } function curriedAdd(num2){ return add(5,num2); } alert(add(2,3)); alert(curriedAdd(3))
|
1 2 3 4 5 6 7 8 9
| function curry(fn){ let args = Array.prototype.slice.call(arguments,1); return function(){ let innerArgs = Array.prototype.slice.call(arguments); let finalArgs = args.concat(innerArgs); return fn.apply(null,finalArgs); } }
|
1 2 3 4 5
| function add(num1,num2){ return num1+num2; } var curriedAdd = curry(add,5); alert(curriedAdd(3));
|
JS中的柯里化函数和绑定函数提供了强大的动态函数创建功能,使用curry还是bind要根据是否需要object对象响应来决定。
它们都能用于创建复杂的算法和功能,当然两者都不应滥用,因为每个函数都会带来额外的开销