JS继承和函数式编程的curry等(227)

原型链

  • 每个函数对象有个一个prototype(显式原型),指向constructor;但constructor.prototype指向本身.
  • 实例只有__proto__(隐式原型)
  • 所有实例需要共享的属性和方法,都可放在prototype;不需要则放在构造函数中
  • 实例的__proto__指向构造该对象的构造函数的原型即**.prototype

es5 6种继承

来自原型对象的引用属性是所有实例共享的

1
2
3
4
5
function Super() {
this.val = 1;
this.arr = [1];
}
function Sub() {...}
  • 简单链

    1
    2
    3
    4
    5
    6
    7
    Sub.prototype = new Super();//共享原型对象,arr是引用类型
    var sub1 = new Sub();
    var sub2 = new Sub();
    //1.无法构造函数传参
    sub1.val = 2;//不会影响sub2
    sub1.arr.push(2);//会影响sub2

    补充
    对继承的简单链原理补充
    我一直在想那样的影响为何有,今天想通了,来做点笔记

    补充:

    • call: 替换上下文,可以想象成替换this
    • new:
      1
      2
      3
      var obj = {};
      obj.__proto__ = Base.prototype;
      Base.call(obj);

    call替换后,它还会再调用一遍Base函数,保证有成员变量

    过程分析:

    • 第一行的new Super直接导致Sub.prototype拥有了valarr
    • 二三行的new Sub只是将__proto__指向了Sub.prototype

    所以使用sub.val sub.arr却也只是访问Sub.prototype上面的东西而已

    如此说来,大家都访问一个东西却为何val不影响呢?

    因为在第6行里是个创建而不是修改

    第六行是对sub1创建一个私有属性并赋值
    第七行是访问sub1arr,然而没有从原型链上拿去了

    • 简单链很好,就怕某地出错,记住它们是访问一个
    • 借用构造函数这个太浪费了不考虑
    • new的数量不是很多倒是可以用用组合继承
  • 借用构造函数

    1
    2
    3
    4
    5
    function Super(val) {...}
    function Sub(val) {
    Super.call(this, val); //1.子类互不影响 2.但是复制了父类实例属性导致内存增加 3.call不会复制原型链
    }
    var sub1 = new Sub();
  • 组合继承

    1
    2
    3
    4
    5
    6
    7
    8
    function Super(val) {...}
    Super.prototype.fun1 = function(){};//函数全放入原型中,方便共享
    function Sub(val) {
    Super.call(this, val);//保留传参功能
    }
    Sub.prototype = new Super();//1. 函数复用 2.构造函数传参 3.原型多余内存
    var sub1 = new Sub(1);
  • 寄生组合继承

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function Super(val) {...}
    Super.prototype.fun1 = function(){};
    function Sub(val) {
    Super.call(this, val);
    }
    function beget(obj) { //构建只有原型链的空对象
    var F = function() {};
    F.prototype = obj;
    return new F();
    }
    var proto = beget(Super.prototype);
    proto.constructor = Sub;
    Sub.prototype = proto;
    var sub = new Sub();//1.确实解决了以上所有问题 2.书写太麻烦了
  • 原型(感觉没意义)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function beget(obj) {
    var F = function(){};
    F.prototype = obj;
    return new F();
    }
    var sup = new Super();
    var sub = beget(sup);
    sub.v = v;
    ...

es6继承

上面的寄生组合继承同,多个static定义静态属性

Curry

这个概念是存储传入参数,够了才执行函数

1
2
3
4
5
6
let fun = a=> b=> c=> {return a+b+c}//注意return
let fun1 = fun(1)//存储函数
let fun2 = fun1(2);
let fun3 = fun2(3);//6
let fun1 = fun(1)(2)(3)//6, 参数多了会报错

compose

这个es6并没有实现,但是很多库有这个函数

1
2
3
4
5
var greeting = (firstName, lastName) => 'hello, ' + firstName + ' ' + lastName
var toUpper = str => str.toUpperCase()
var fn = compose(toUpper, greeting)
console.log(fn('jack', 'smith'))
// ‘HELLO,JACK SMITH’

  • compose的参数是函数,返回的也是一个函数
  • 因为除了第一个函数的接受参数,其他函数的接受参数都是上一个函数的返回值,所以初始函数的参数是多元的,而其他函数的接受值是一元的
  • compsoe函数可以接受任意的参数,所有的参数都是函数,且执行方向是自右向左的,初始函数一定放到参数的最右面
// //