Skip to content

Instantly share code, notes, and snippets.

@hjzheng
Last active March 17, 2016 03:26
Show Gist options
  • Save hjzheng/46fcecb34d09785f9181 to your computer and use it in GitHub Desktop.
Save hjzheng/46fcecb34d09785f9181 to your computer and use it in GitHub Desktop.

函数(剩余内容)

高阶函数 是指操作函数的函数,它接收一个或多个函数作为参数,并返回一个新函数

//返回一个新的可以计算f(g())的函数
function compose(f,g){
  return function(){
    //需要给f()传入一个参数,所以用call
    //需要给g()传入很多参数,所以用apply
    return f.call(this, g.apply(this, arguments));
  }
}

var square = function(x){ return x*x };
var sum = function(x, y){ return x+y };
var squareOfSum = compose(square, sum);
squareOfSum(2, 3); //5

partial

//partial
function arr(a, n){
  return Array.prototype.slice.call(a, n||0);
}

function partialLeft(f /*, ...*/){
  var args = arguments;
  return function(){
    var a = arr(args, 1); //干掉第一个参数 f, 拿剩下的
    return f.apply(this, a.concat(arr(arguments)));
  };
}

function partialRight(f /*, ...*/){
  var args = arguments;
  return function(){
    var a = arr(args, 1); //干掉第一个参数 f, 拿剩下的
    return f.apply(this, arr(arguments).concat(a));
  };
}

function partial(f /*, ... ...*/) {
  var args = arguments;
  return function(){
    var a = arr(args, 1); //干掉第一个参数 f, 取剩下的
    var i = 0, j = 0;
    //遍历args, 从内部实参填充undefined元素
    for(; i<a.length; i++){
      if(a[i] === undefined) a[i] = arguments[j++];
    }
    
    // 将剩下的参数追加进来
    a = a.concat(array(arguments, j));
    return f.apply(this, a);
  };
}

var f = function(x, y, z) { return x * (y-z)};

partialLeft(f, 1)(2, 3) //1*(2-3)
partialRight(f, 1)(2, 3) //2*(3-1)
partial(f, undefined, 1)(2, 3) //2*(1-3)

memorization

function memorize(f){
  var cache = {};//将值保存在闭包内
  return function(){
    var key = arguments.length + Array.prototype.join.call(arguments, ",");
    if (key in cache) {
      return cache[key];
    } else {
      return cache[key] = f.apply(this, arguments);
    }
  };
}

function sum(){
  var args = Array.prototype.slice.call(arguments);
  var s = 0;
  args.forEach(function(v){
    s += v;
  });
  return s;
}

var mySum = memorize(sum);
mySum(1,51,34);

类和模块

下面是修改的正确的例子

function Range(from, to){
    this.from = from;
    this.to = to;
}

Range.prototype = {
    includes: function(x){
        return this.from <= x && x <= this.to;
    },
    foreach: function(f) {
        for(var x = Math.ceil(this.from); x <= this.to; x++) 
            f(x); 
    },
    toString: function(){
        return "(" + this.from + "..." + this.to + ")";
    }
}



var r = new Range(1, 3);
r.includes(2);
r.foreach(console.log.bind(console));
console.log(r.toString());
  • 构造函数和类的标识 原型对象是类的唯一标识;而且仅当两个对象继承自同一个原型对象时,它们才属于同一个类的实例
r instanceof Range //r如果继承自Range.prototype, 则返回true

实际上instanceof并不会检查是否是由Range()构造函数初始化而来,而是检查r是否继承自Range.prototype

  • constructor属性 每个JavaScript函数(除ES5 Function.bind()方法返回的函数除外)都自动拥有一个prototype属性。这个属性的值是一个对象, 这个对象包含为一一个不可枚举的属性constructor。constructor属性的值是一个函数的对象
var F = function(){}
var p = F.prototype;
var c = p.constructor;
c === F //true F.prototype.constructor == F
var o = new F();
o.constructor == F //true

因此Range.prototype定义的话,为了防止constructor等被覆盖掉,采用下面的方式

Range.prototype.includes = function(x) { 
    return this.from<=x && x<=this.to; 
};
Range.prototype.foreach = function(f) {
    for(var x = Math.ceil(this.from); x <= this.to; x++) 
    f(x); 
};
Range.prototype.toString = function() {
    return "(" + this.from + "..." + this.to + ")";
};

JavaScript中的Java式的类继承

在JavaScript中定义类的步骤,有三部

  • 定义一个构造函数,并初始化新对象的实例属性
  • 给构造函数prototype上定义实例方法
  • 给构造函数定义类字段和属性
function extend(o, p){
  for(prop in p){
    o[prop] = p[prop]
  }
  return o;
}

function defineClass(constructor, methods, statics){
  if(methods){extend(constructor.prototype, methods)}
  if(statics){extend(constrcutor, statics)}
  return constrcutor;
}

var SimpleRange = defineClass(function(f, t){this.f = f; this.t = t;},
                    {
                      includes: function(x){/*省略*/},
                      toString: function(){/*省略*/}
                    },
                    {
                      upto: function(t){/*省略*/}
                    });

类的扩充

我们可以很轻松的对原型进行改造,添加方法,这样继承原型的所有实例对象会有相应的方法

String.prototype.trim = String.prototype.trim || function(){
  if(!this) return this;
  return this.replace(/^\s+|\s+$/g, "");
};

Function.prototype.getName = function(){
  return this.name || this.toString().match(/function\s*([^()*]\(/))/)[1];
}

类和类型

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment