js中所有的function都是对象,可以利用指针搞事情。
- 安全的类型检测:
typeof不可靠,比如正则类型可能返回"function"。instanceof在存在多个全局作用域情况下(例如多个frame)也不可靠。如何检测某个对象是原生对象还是开发者自定义对象?
以上答案:
通过调用Object对象的原生方法toString,能返回[object NativeConstructorName],每个对象有个内部属性[[Class]],其值为构造器的名称。
例:var x = "abc";
var type = Object.prototype.toString.call(x); //type的值为"[object String]"
Object的toString方法不能检测非原生构造函数的构造函数名,因此自定义的任何构造函数都将返回[object Object]。
注意:Object的toString方法本身可能被篡改! - 作用域安全的构造器:
构造器就是使用new操作符的函数,构造器内的this对象指向新创建的对象实例。如果忽略new操作符,内部的this指针绑定到运行时的window对象,可能导致错误。因此需要作用域安全的构造器。
使用作用域安全的构造器首先要判断this对象是否是该构造器的实例。
注意:如果使用作用域安全的构造器,则会锁定调用构造器的环境。如果使用构造器窃取(constructor-stealing)模式的继承而不使用原型链,则继承可能被破坏。
解决方式:构造函数窃取模式结合原型链(prototype chain)或寄生组合(parasitic combination)。 - 惰性加载函数:
问题:避免每次判断不必要的if语句。
惰性加载表示函数执行的分支只发生一次。两种实现方式:1.在函数首次执行时处理,该函数被覆盖为按合适方式执行的函数,方便未来调用不经过条件分支,会在首次执行时损失性能;2.在函数声明时处理,通过匿名函数方式返回合适的执行函数,代码首次加载时会损失性能。 - 函数绑定:
创建一个可以通过特定的this值和特定的参数调用另一个函数的函数。常与回调和事件处理器一起使用,以便将函数作为变量传递时同时保留代码执行环境。
方式:1.闭包;2.创建将函数绑定到指定环境的函数。
js库提供可将函数绑定到指定环境的函数:bind(),bind()函数创建一个闭包,闭包通过使用apply()调用传入的函数fn,并给apply()传递上下文对象(context)和arguments参数。注意:arguments参数是返回的匿名函数的参数,不是bind的参数。
function bind(fn, context){
return function(){
return fn.apply(context, arguments);
};
}
ES5为所有函数定义了原生的bind()方法:fn.bind(context)。传入上下文对象(context)作为this值。被绑定函数与普通函数相比有更多开销,因为函数的多重调用需要更多内存。 - 函数柯里化(Currying):
柯里化定义:柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后,部分应用参数,并返回一个更具体的函数接受剩下的参数,中间可嵌套多层这样的接受部分参数函数,逐步缩小函数的适用范围,逐步求解,直至返回最后结果。
js的函数柯里化用于创建已经设置好了1个或多个参数(部分函数应用)的函数。基本思路与函数绑定相同:使用闭包返回一个函数。区别:当柯里化后的函数被调用时,需要设置传入参数。
ES5的bind()函数已实现函数柯里化,只要在this后传入参数即可。
function bind(fn, context) {
return function() {
return fn.apply(context, arguments);
}
}
function curry(fn) {
var _arg = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(null, _arg.concat(Array.prototype.slice.apply(arguments)));
}
}
//方式1
function sum() {
var sum = 0;
var _arg = Array.prototype.slice.apply(arguments);
for (var i = 0; i < _arg.length; i++) {
sum += _arg[i];
}
return function() {
var _innerArg = Array.prototype.slice.apply(arguments);
if (_innerArg.length > 0) {
for (var i = 0; i < _innerArg.length; i++) {
sum += _innerArg[i];
}
return arguments.callee;
} else {
return sum;
}
}
}
var x = sum(1,2,3)(0)(3,4,5)();
console.log(x);
//方式2
function currySum(fn) {
var _args = [];
return function() {
var _innerArg = Array.prototype.slice.apply(arguments);
if (_innerArg.length === 0) {
return fn.apply(null, _args);
} else {
_args = _args.concat(_innerArg);
return arguments.callee;
}
}
}
function sum2() {
var _arg = Array.prototype.slice.apply(arguments);
var sum = 0;
for (var i = 0; i < _arg.length; i++) {
sum += _arg[i];
}
return sum;
}
var currideSum = currySum(sum2);
var z = currideSum(0,1)(2,3,4,5)(2)(3)();
console.log(z);
function sqr(i) {
return i*i;
}
function map(hdl, list) {
return list.map(hdl);
}
var mapSqr = curry(map, sqr);
网友评论