Chapter 22. 高级技巧篇

2018-08-07  本文已影响0人  weiee

js中所有的function都是对象,可以利用指针搞事情。

  1. 安全的类型检测:
    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方法本身可能被篡改!
  2. 作用域安全的构造器:
    构造器就是使用new操作符的函数,构造器内的this对象指向新创建的对象实例。如果忽略new操作符,内部的this指针绑定到运行时的window对象,可能导致错误。因此需要作用域安全的构造器。
    使用作用域安全的构造器首先要判断this对象是否是该构造器的实例。
    注意:如果使用作用域安全的构造器,则会锁定调用构造器的环境。如果使用构造器窃取(constructor-stealing)模式的继承而不使用原型链,则继承可能被破坏。
    解决方式:构造函数窃取模式结合原型链(prototype chain)或寄生组合(parasitic combination)。
  3. 惰性加载函数:
    问题:避免每次判断不必要的if语句。
    惰性加载表示函数执行的分支只发生一次。两种实现方式:1.在函数首次执行时处理,该函数被覆盖为按合适方式执行的函数,方便未来调用不经过条件分支,会在首次执行时损失性能;2.在函数声明时处理,通过匿名函数方式返回合适的执行函数,代码首次加载时会损失性能。
  4. 函数绑定:
    创建一个可以通过特定的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值。被绑定函数与普通函数相比有更多开销,因为函数的多重调用需要更多内存。
  5. 函数柯里化(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);

上一篇 下一篇

猜你喜欢

热点阅读