js链式调用的实现(返回值)

在看函数的链式调用想到一个问题,那就是链式调用都用this返回当前对象。如果要返回当前对象的值,那么必须自己去取。如以下:

//  随便复制过来的,侵删.
function ClassA(){
    this.prop1 = null;
    this.prop2 = null;
    this.prop3 = null;
}
ClassA.prototype = {
    method1 : function(p1){
        this.prop1 = p1;
        return this;
    },
    method2 : function(p2){
        this.prop2 = p2;
        return this;
    },
    method3 : function(p3){
        this.prop3 = p3;
        return this;
    }
}
var obj = new ClassA(); 
obj.method1(1).method2(2).method3(3); // obj -> prop1=1,prop2=2,prop3=3

那么es6中的filter和map是如何实现的?这两个方法都可以链式调用,而且也能返回操作结果。比如:

let arr = [
  { name: "王小二", id: "12323", sex: "0" },
  { name: "李虎", id: "12332", sex: "1" },
  { name: "王贺", id: "12323", sex: "0" },
];

let newArr = arr.filter((item) => item.sex === "0").map((item) => ({ name: item.name, id: item.id }));

有没有大佬能写一个例子说明一下?谢谢。

阅读 6.1k
3 个回答

第一,这两个方法是 ES5 的,不是 ES6 的(倒是你用的 let 关键字和箭头函数这俩特性是 ES6 的)。

第二,这俩方法只是个会返回一个新数组的方法,严格意义上来说并不是链式调用,链式调用得返回自身。

可以看下 polyfill:

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill
Array.prototype.map = function(callback) {
    var T, A, k;
    var O = Object(this);
    var len = O.length >>> 0;

    if (typeof callback !== 'function') {
        throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
        T = arguments[1];
    }

    A = new Array(len);
    k = 0;
    while (k < len) {
        var kValue, mappedValue;
        if (k in O) {
            kValue = O[k];
            mappedValue = callback.call(T, kValue, k, O);
            A[k] = mappedValue;
        }
        k++;
    }

    return A;
};

链式调用都用this返回当前对象这句话并不正确,你不要把链式调用想的那么复杂,其根本就是数据的属性取值,只要.前面的函数返回的数据可以进行点运算,去自身或原型链上找到属性,然后这个属性是一个函数被运行,这样一直运行下去。所以函数不一定要返回this,比如下面的函数,而返回this也不一定可以链式。js是单线程的,你可以根据.,把链式拆开看

//模拟filter map差不多
Array.prototype.myFilter = function(fn, content){
    var result = [], arr = this
    for(var i = 0; i < arr.length; i++){
        if(fn.call(content, arr[i], i, arr)){
            result.push(arr[i])
        }
    }
    return result
}

链式调用的关键是前一个调用返回值(一个对象)中包含后续调用的方法(定义),并且逐级都是有效的,否则任何一个位置不符合,整个调用就中断。其实它并不一定关联到this,也不是一定要求返回this,可能是和this相关处理后的数据,甚至和this无关也是可以的。

Number.prototype.Add = function(inb){
    let a=this;
    return (a+inb);
}
console.log( (6).Add(8).Add(14))

注意这里第1个数字6加了括号,如果不加括号会出错,因为数字直接加点可能是想表示小数,这里加了括号就消除了歧义。

你提到的数组对象filter和map处理后支持操作链式操作,其实也是类似的情况。
数组的filter和map处理其实都是产生了新的数组对象返回,因为filter和map这两个方法都是绑定到数组上的方法,所以只要是数组都可以支持它们,从而形成链式操作支持。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题