JS如何实现XDM

这篇文章主要介绍“JS如何实现XDM”,在日常操作中,相信很多人在JS如何实现XDM问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JS如何实现XDM”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

偏函数

传参现状

我们经常会写出这样的代码:

function ajax(url,data,callback) {
    // ..
}
function getPerson(data,cb) {
    ajax( "http://some.api/person", data, cb );
}

ajax 函数有三个入参,在 getPerson 函数里调用,其中 url 已确定,data 和 cb 两个参数则等待传入。(因为很多时候参数都不是在当前能确定的,需要等待其它函数的操作后确定了再继续传入)

但是我们的原则是:入参最理想的情况下只需一个!

怎样优化,可以实现这一点呢?

我们或许可以在外层再套一个函数来进一步确定传参,比如:

function getCurrentUser(cb) {
    ...// 通过某些操作拿到 CURRENT_USER_ID
    getPerson( { user: CURRENT_USER_ID }, cb );
}

这样,data 参数也已经确定,cb 参数仍等待传入;函数 getCurrentUser 就只有一个入参了!

数据的传递路线是:

ajax(url,data,callback) => getPerson(data,cb) => getCurrentUser(cb)

这样函数参数个数逐渐减少的过程就是偏应用。

也可以说:getCurrentUser(cb) 是 getOrder(data,cb) 的偏函数,getOrder(data,cb) 是 ajax(url,data,cb) 函数的偏函数。

设想下:

如果一个函数是这样的:

function receiveMultiParam(a,b,c,......,x,y,z){
    // ..
}

我们难道还要像上面那样手动指定外层函数进行逐层嵌套吗?

显示我们不会这么做!

封装 partial

我们只需要封装一个 partial(..) 函数:

function partial(fn,...presetArgs) {
    return function partiallyApplied(...laterArgs){
        return fn( ...presetArgs, ...laterArgs );
    };
}

它的基础逻辑是:

var partial =
    (fn, ...presetArgs) =>
        (...laterArgs) =>
            fn( ...presetArgs, ...laterArgs );

把函数作为入参!还记得我们之前所说:

一个函数如果可以接受或返回一个甚至多个函数,它被叫做高阶函数。

我们借用 partial() 来实现上述举例:

var getPerson = partial( ajax, "http://some.api/person" );
var getCurrentUser = partial( getPerson, { user: CURRENT_USER_ID } ); // 版本 1

以下函数内部分析非常重要:

运行机制

getPerson() 的内部运行机制是:

var getPerson = function partiallyApplied(...laterArgs) {
    return ajax( "http://some.api/person", ...laterArgs );
};

getCurrentUser() 的内部运行机制是:

var getCurrentUser = function outerPartiallyApplied(...outerLaterArgs) {
    var getPerson = function innerPartiallyApplied(...innerLaterArgs){
        return ajax( "http://some.api/person", ...innerLaterArgs );
    };
    return getPerson( { user: CURRENT_USER_ID }, ...outerLaterArgs );
}

数据进行了传递:

getCurrentUser(outerLaterArgs) => getPerson(innerLaterArgs) => ajax(...params)

我们通过这样一层额外的函数包装层,实现了更加强大的数据传递,

我们将需要减少参数输入的函数传入 partial()中作为第一个参数,剩下的是 presetArgs,当前已知几个,就可以写几个。还有不确定的入参 laterArgs,可以在确定后继续追加。

像这样进行额外的高阶函数包装层,是函数式编程的精髓所在!

“随着本系列的继续深入,我们将会把许多函数互相包装起来。记住,这就是函数式编程!” —— 《JavaScript 轻量级函数式编程》

实际上,实现 getCurrentUser() 还可以这样写:

// 版本 2
var getCurrentUser = partial(
    ajax,
    "http://some.api/person",
    { user: CURRENT_USER_ID }
);
// 内部实现机制
var getCurrentUser = function partiallyApplied(...laterArgs) {
    return ajax(
        "http://some.api/person",
        { user: CURRENT_USER_ID },
        ...laterArgs
    );
};

但是版本 1 因为重用了已经定义好的函数,所以它在表达上更清晰一些。它被认为更加贴合函数式编程精神!

拓展 partial

我们再看看 partial() 函数还可它用:

function partial(fn,...presetArgs) {
    return function partiallyApplied(...laterArgs){
        return fn( ...presetArgs, ...laterArgs );
    };
}

比如:将数组 [1,2,3,4,5] 每项都加 3,通常我们会这么做:

function add(x,y) {
    return x + y
[1,2,3,4,5].map( function adder(val){
    return add( 3, val );
} );
// [4,5,6,7,8]

借助 partial():

[1,2,3,4,5].map( partial( add, 3 ) );
// [4,5,6,7,8]

add(..) 不能直接传入 map(..) 函数里,通过偏应用进行处理后则能传入;

实际上,partial() 函数还可以有很多变体:

回想我们之前调用 Ajax 函数的方式:ajax( url, data, cb )。如果要偏应用 cb 而稍后再指定 data 和 url 参数,我们应该怎么做呢?

function reverseArgs(fn) {
    return function argsReversed(...args){
        return fn( ...args.reverse() );
    };
}
function partialRight( fn, ...presetArgs ) {
    return reverseArgs(
        partial( reverseArgs( fn ), ...presetArgs.reverse() )
    );
}
var cacheResult = partialRight( ajax, function onResult(obj){
    cache[obj.id] = obj;
});
// 处理后:
cacheResult( "http://some.api/person", { user: CURRENT_USER_ID } );

柯里化

函数柯里化实际上是一种特殊的偏函数。

我们用 curry(..) 函数来实现此前的 ajax(..) 例子,它会是这样的:

var curriedAjax = curry( ajax );
var personFetcher = curriedAjax( "http://some.api/person" );
var getCurrentUser = personFetcher( { user: CURRENT_USER_ID } );
getCurrentUser( function foundUser(user){ /* .. */ } );

柯里化函数:接收单一实参(实参个数:1)并返回另一个接收下一个实参的函数。

它将一个函数从可调用的 f(a, b, c) 转换为可调用的 f(a)(b)(c)。

实现:

function curry(fn,arity = fn.length) {
    return (function nextCurried(prevArgs){
        return function curried(nextArg){
            var args = prevArgs.concat( [nextArg] );
            if (args.length >= arity) {
                return fn( ...args );
            }
            else {
                return nextCurried( args );
            }
        };
    })( [] );
}

到此,关于“JS如何实现XDM”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注本站网站,小编会继续努力为大家带来更多实用的文章!

相关推荐:

哪里有MC.js秒玩入口

在游戏的世界中,我们始终渴望更高效、更省心的启动方式,而mc.js秒玩入口正为玩家献上这份即刻开玩的畅快体验。 一键启程,告别繁琐流程 借助mc.js秒玩入口,无需下载客户端、无需复杂安装步骤。只需一次点击,即可瞬间进入《我的世界》——这个由方块构筑、充满无限想象的开放世界。彻底摆脱冗长的加载与配置等待,玩家能即刻投入建造、探索、生存与冒险之中。无论是构思一座高耸入云的空中要塞,还是深入幽暗矿洞直...

mc.js无需安装网页版点开即玩 点开即进入MCJS网页版

mcjs网页版点开即玩,无需安装,访问https://www.mc.js.cool/即可;采用webassembly技术、客户端运算、多浏览器支持、智能设备适配,并内置120+世界模板与丰富操作功能。 mc.js无需安装网页版点开即玩 点开即进入MCJS网页版,这是近期许多Minecraft爱好者热议的话题,接下来由PHP小编为大家带来MCJS网页版的直接访问方式与实用体验细节,感兴趣的玩家一起随...

JS中search与replace方法入门

互联网技术的不断发展让编程变得更加普及,掌握一门编程语言能够有效提升工作效能。 1、 创建一个HTML文件,搭建网页的基本框架,包括标题区域和主体内容部分。 2、 search() 方法用于在字符串中查找特定子串或符合正则表达式的内容,并返回其第一次匹配到的起始索引位置。 3、 保存代码后在浏览器中打开,通过点击页面上的按钮来进行功能测试。 4、 该方法可用于将字符串中指定的字符替换为新的字符,也...

MC.js秒玩入口

MC.js秒玩入口:https://classic.minecraft.net/,MC.js是一款风靡全球的3D沙盒游戏,以其无与伦比的自由度、创造力与开放玩法而闻名。游戏采用第一人称或第三人称视角,提供了一个随机生成、近乎无限的方块世界,供玩家单人或与朋友联机探索、建造与生存。 MC.js秒玩入口 MC.js秒玩入口:https://classic.minecraft.net/ 核心游戏特色与玩...

python 怎么调用js

Python无法直接执行JavaScript,需借助浏览器引擎(如Selenium/Playwright)或Node.js运行时实现调用:Selenium适用于依赖DOM、浏览器API的场景;subprocess调用Node.js适合纯逻辑计算;长期项目推荐JS服务化。 Python 本身不能直接执行 JavaScript 代码,但可以通过几种常见方式“调用 JS”——本质是让 JS 在某个环境中...
· Python · 187058

mc.js H5游戏 mc.js HTML5版入口

mc.js H5游戏入口位于https://mcjs.org,该平台基于HTML5技术,支持免下载在线游玩,适配移动端与桌面端,采用JavaScript与Canvas实现流畅渲染,具备快速加载、触控与键盘双操作模式、本地存档及自定义创作功能,用户体验简洁便捷。 mc.js H5游戏 mc.js HTML5版入口在哪里?这是不少网友都关注的,接下来由PHP小编为大家带来mc.js H5游戏的访问方式...

使用 Node.js 连接 LDAP 进行 NTLM 身份验证

本文档介绍了如何在 Node.js 中使用 LDAP 协议结合 NTLM 身份验证,通过服务账号绑定和用户DN检索的方式实现用户登录验证。文章将详细阐述连接 LDAP 服务器、搜索用户 DN 以及验证用户密码的步骤,并提供相应的代码示例,帮助开发者理解并实现基于 LDAP 的用户身份验证功能。 在 Node.js 中集成 LDAP 身份验证,特别是需要使用 NTLM 协议时,可能会遇到一些挑战。不...
· Python · 172687

js中sqlalchemy的实例详解

sqlalchemy的返回类型有大都有两种,一种是model对象,一种是query集合(只查询部分字段)。 针对这两种返回结果,都是来自同一中类型  sqlalchemy.orm.query.Query  所以针对Query做相应处理,让他返回一个dict   class AlchemyJsonEncoder(json.JSONEncoder): def default(self, obj): #...
· Python · 270648