javascript函数式

by rajaraodv

通过rajaraodv

JavaScript中的函数式编程—结合实际示例(第2部分) (Functional Programming In JavaScript — With Practical Examples (Part 2))

In Part 1, we talked through: Functional Programming basics, Currying, Pure Functions, “Fantasy-land” specs, “Functors”, “Monads”, “Maybe Monads” and “Either Monads” via couple of examples.

在第1部分中 ,我们讨论了:函数式编程基础知识,Currying,纯函数,“幻想世界”规范, 通过几个示例可以看出“ Functors”,“ Monads”,“ Maybe Monads”和“ Either Monads”。

In this part, we’ll cover: Applicative, curryN function and “Validation Applicative”.

在这一部分中,我们将介绍:应用程序,curryN函数和“验证应用程序”。

Thanks to FP gurus Brian Lonsdorf, keithalexander and others for reviewing ??

感谢FP专家Brian Bons Lonsdorf , keithalexander和其他人对??

示例3 —将值分配给可能为空的对象 (Example 3— Assigning Values To Potentially Null Objects)

FP Concepts Used: “Applicative”

使用的FP概念:“适用”

Use Case: Let’s say we want to give discount to the user if the user is logged in and if we are running promotion (i.e. discount exists).

用例:假设我们要给用户折扣,如果用户已登录并且我们正在促销(即存在折扣)。

Let’s say we are using the applyDiscount method below. As you can imagine, applyDiscount might throw null errors if either the user (the left-hand side or the discount (the right-hand side) is null.

假设我们正在使用下面的applyDiscount方法。 可以想象,如果用户(左侧)或折扣(右侧)为null,则applyDiscount可能会引发null错误。

//Adds discount to the user object if BOTH user and discount exists.//Throws null errors if either user or discount is nullconst applyDiscount = (user, discount) => {    let userClone = clone(user);// use some lib to make a copy     userClone.discount = discount.code;   return userClone;}

//Adds discount to the user object if BOTH user and discount exists. //Throws null errors if either user or discount is nullconst applyDiscount = (user, discount) => { let userClone = clone(user);// use some lib to make a copy userClone.discount = discount.code; return userClone; userClone.discount = discount.code; return userClone; }

Let’s see how we can solve this using “applicative”.

让我们看看如何使用“应用程序”解决此问题。

Applicative:

适用范围:

Any Class that have a method “ap” and implements the Applicative spec is called an Applicative. Applicatives can be used in functions that are dealing with null values on both left-hand-side(user) and right-hand-side(discount) of the equation.

具有方法“ ap”并实现应用规范的任何类都称为应用。 可以在等式的左侧(用户)和右侧(折扣)上处理空值的函数中使用应用程序。

It turns out “Maybe” Monads (and every Monads) also implement “ap” spec and hence are also “Applicatives” and not just Monads. So we can use “Maybe” Monads to deal with null at function level.

事实证明,“也许” Monads(以及每个Monads)也执行“ ap”规范,因此也是“ Applicatives”,而不仅仅是Monads。 因此,我们可以在函数级别使用“也许”单声道来处理null。

Let’s see how we can solve make applyDiscount work using Maybe used as an “applicative”.

让我们看看如何使用Maybe用作“应用程序”来解决使applyDiscount工作的问题。

步骤1:在Maybe Monads中包装潜在的空值 (Step 1: wrap our potential null values in Maybe Monads)

const maybeUser = Maybe(user);const maybeDiscount = Maybe(discount);

const maybeUser = Maybe(user); const maybeDiscount = Maybe(discount);

第2步:重写函数并对其进行咖喱处理,以便我们一次可以传递一个参数。 (Step 2: Rewrite the function and curry it so we can pass one param at a time.)

//Rewrite the function and curry it so we can //pass one param at a timevar applyDiscount = curry(function(user, discount) {           user.discount = discount.code;           return user; });

//Rewrite the function and curry it so we can //pass one param at a time var applyDiscount = curry(function(user, discount) { user.discount = discount.code; return user; });

步骤3:让我们通过“地图”将第一个参数(maybeUser)传递给applyDiscount。 (Step 3: let’s pass the first argument(maybeUser) to applyDiscount via “map”.)

//pass the first argument to applyDiscount via "map"const maybeApplyDiscountFunc = maybeUser.map(applyDiscount);//Note, since applyDiscount is "curried", and "map" will only pass 1 parameter, the return result (maybeApplyDiscountFunc) will be a Maybe wrapped "applyDiscount" function that now has maybeUser(1st param) in it's closure.In other words, we now have a function wrapped in a Monad!

//pass the first argument to applyDiscount via "map" const maybeApplyDiscountFunc = maybeUser.map(applyDiscount); //Note, since applyDiscount is "curried", and "map" will only pass 1 parameter, the return result ( maybeApplyDiscountFunc ) will be a Maybe wrapped "applyDiscount" function that now has maybeUser(1st param) in it's closure. In other words, we now have a function wrapped in a Monad! const maybeApplyDiscountFunc = maybeUser.map(applyDiscount); //Note, since applyDiscount is "curried", and "map" will only pass 1 parameter, the return result ( maybeApplyDiscountFunc ) will be a Maybe wrapped "applyDiscount" function that now has maybeUser(1st param) in it's closure. In other words, we now have a function wrapped in a Monad!

步骤4:处理 maybeApplyDiscountFunc (Step 4: Deal With maybeApplyDiscountFunc)

At this stage maybeApplyDiscountFunc can be:1. If user actually exists, then maybeApplyDiscountFunc is a function wrapped inside a Maybe.2. If the user does not exist, then maybeApplyDiscountFunc will be “Nothing” (subclass of Maybe)

在这个阶段,applyDiscountFunc可以是: 1.如果用户确实存在,那么applyDiscountFunc是包装在Maybe中的函数。 2.如果用户不存在,则ApplyDiscountFunc可能为“ Nothing”(Maybe的子类)

If user doesn’t exist, then “Nothing” is returned and any further interaction with this are ignore completely. So if we pass 2nd argument, nothing happens. And also no Null errors are thrown.

如果用户不存在,则返回“ Nothing”,并且与之进行的任何进一步交互都将被完全忽略。 因此,如果我们通过第二个参数,则什么也不会发生。 而且也不会抛出Null错误。

But in the case where the user actually exists, we can try to pass the 2nd argument to maybeApplyDiscountFunc via “map” to execute the function like below:

但是在用户实际存在的情况下,我们可以尝试通过“ map”将第二个参数传递给maybeApplyDiscountFunc,以执行如下功能:

maybeDiscount.map(maybeApplyDiscountFunc)! // PROBLEM!

maybeDiscount.map(maybeApplyDiscountFunc)! // PROBLEM!

Uh oh! “map” doesn’t know how to run function(maybeApplyDiscountFunc) when the function itself is inside a MayBe!

哦! 当功能本身在MayBe内时, “地图”不知道如何运行功能(也许是ApplyDiscountFunc)!

That’s why we need a different interface to deal with this scenario. It turns out that’s “ap”!

这就是为什么我们需要一个不同的界面来处理这种情况的原因。 原来那是“ ap”!

Step5: Let’s recap “ap” function. “ap” method takes another Maybe monad and passes/applies the function it’s currently storing to that Maybe.

步骤5:让我们回顾一下“ ap”功能。 “ ap”方法采用另一个Maybe monad,并将当前存储的功能传递/应用到该Maybe。

So we can simply apply (“ap”) maybeApplyDiscountFunc to maybeDiscount instead of using “map” like below and it’ll work like a charm!

因此,我们可以简单地将(app)DistanceApplyDiscountFunc应用于(也许)而不是像下面那样使用“ map”,它将像魅力一样起作用!

maybeApplyDiscountFunc.ap(maybeDiscount)//Internally it is doing the following because applyDiscount is store in the this.val of maybeApplyDiscountFunc wrapper:maybeDiscount.map(applyDiscount)//Now, if maybeDiscount actually has the discount, then the function is is run.If maybeDiscount is Null, then nothing happens.

maybeApplyDiscountFunc. ap (maybeDiscount)//Internally it is doing the following because applyDiscount is store in the this.val of maybeApplyDiscountFunc wrapper: maybeApplyDiscountFunc. ap (maybeDiscount)//Internally it is doing the following because applyDiscount is store in the this.val of maybeApplyDiscountFunc wrapper: maybeDiscount.map(applyDiscount)//Now, if maybeDiscount actually has the discount, then the function is is run.If maybeDiscount is Null, then nothing happens.

FYI: Apparently there is a change in the FL spec, The old version has (eg): `Just(f).ap(Just(x))` (where `f` is a function and `x` is a value) but the new version would have you write `Just(x).ap(Just(f))`But the implementations mostly haven’t changed yet. Thanks keithalexander

仅供参考:显然FL规范有所变化,旧版本有(例如):`Just(f).ap(Just(x))`(其中`f`是函数,`x`是值)但是新版本将要求您编写`Just(x).ap(Just(f))`,但实现方式大部分尚未改变。 谢谢keithalexander

To summarize, if you have a function that deals with multiple parameters that might all be null, you curry it first, then put it inside a Maybe. Further, also put all params in a Maybe and then use “ap” to run the function.

总而言之,如果您有一个处理多个可能都为空的参数的函数,则首先对其进行咖喱处理,然后将其放入Maybe中。 此外,还将所有参数放在Maybe中,然后使用“ ap”运行该函数。

咖喱功能 (curryN function)

We are familiar with “curry”. It simply converts a function that takes multiple arguments to take them one-by-one.

我们熟悉“咖喱”。 它只是简单地转换了一个函数,该函数需要多个参数才能将它们一对一地接受。

//Curry Example:const add = (a, b) =>a+b;const curriedAdd = R.curry(add);const add10 = curriedAdd(10);//pass the 1st argument. Returns a function that takes 2nd (b) parameter.//run function by passing 2nd argumentadd10(2) // -> 12 //internally runs "add" with 10 and 2.

//Curry Example: const add = (a, b) =>a+b;const curriedAdd = R.curry(add);const add10 = curriedAdd(10);//pass the 1st argument. Returns a function that takes 2nd (b) parameter.//run function by passing 2nd argument const add = (a, b) =>a+b;const curriedAdd = R.curry(add);const add10 = curriedAdd(10);//pass the 1st argument. Returns a function that takes 2nd (b) parameter.//run function by passing 2nd argument add10(2) // -> 12 //internally runs "add" with 10 and 2. const add = (a, b) =>a+b;const curriedAdd = R.curry(add);const add10 = curriedAdd(10);//pass the 1st argument. Returns a function that takes 2nd (b) parameter.//run function by passing 2nd argument add10(2) // -> 12 //internally runs "add" with 10 and 2.

But instead of adding just two numbers, what if the add function can sum up all the numbers passed to it as an argument?

但是,如果不两个数字相加,那么add函数可以将作为参数传递给它的所有数字相加呢?

const add = (...args) => R.sum(args); //sum all the numbers in args

const add = (...args) => R.sum(args); //sum all the numbers in args

We can still curry it by limiting number of args using curryN like below:

我们仍然可以通过使用curryN限制arg的数量来咖喱它,如下所示:

//curryN exampleconst add = (...args) => R.sum(args);//CurryN Example:const add = (...args) => R.sum(args);const add3Numbers = R.curryN(3, add);const add5Numbers = R.curryN(5, add);const add10Numbers = R.curryN(10, add);add3Numbers(1,2,3) // 6add3Numbers(1) // returns a function that takes 2 more params.add3Numbers(1, 2) // returns a function that take 1 more param.

//curryN example const add = (...args) => R.sum(args);//CurryN Example: const add = (...args) => R.sum(args);const add3Numbers = R. curryN (3, add); const add5Numbers = R. curryN (5, add); const add10Numbers = R. curryN (10, add);add3Numbers(1,2,3) // 6 add3Numbers(1) // returns a function that takes 2 more params. add3Numbers(1, 2) // returns a function that take 1 more param.

使用“ curryN”等待函数调用次数 (Using “curryN” to wait for number of function calls)

Let’s say we want to write a function that only logs if we call it 3 times (and ignore the 1st and 2nd call). Something like below:

假设我们要编写一个仅在调用3次后才记录日志的函数(而忽略第一次和第二次调用)。 如下所示:

//impurelet counter = 0;const logAfter3Calls = () => { if(++counter == 3)   console.log('called me 3 times');}logAfter3Calls() // Nothing happenslogAfter3Calls() // Nothing happenslogAfter3Calls() // 'called me 3 times'

//impure let counter = 0; const logAfter3Calls = () => { if(++counter == 3) console.log('called me 3 times'); const logAfter3Calls = () => { console.log('called me 3 times'); }logAfter3Calls() // Nothing happens logAfter3Calls() // Nothing happens logAfter3Calls() // 'called me 3 times'

We can simulate that using curryN like below.

我们可以使用curryN进行模拟,如下所示。

//Pureconst log = () => {   console.log('called me 3 times');}const logAfter3Calls = R.curryN(3, log);//calllogAfter3Calls('')('')('')//'called me 3 times'//Note: We are passing '' to satisfy CurryN that we are passing some parameter.

//Pure const log = () => { console.log('called me 3 times'); } const logAfter3Calls = R.curryN(3, log); //call } const logAfter3Calls = R.curryN(3, log); //call logAfter3Calls('')('')('') //'called me 3 times'//Note: We are passing '' to satisfy CurryN that we are passing some parameter.

Note: We’ll be using this technique in the Applicative validation.

注意:我们将在Applicative验证中使用此技术。

示例4 —收集和显示多个错误 (Example 4— Collecting And Displaying Multiple Errors)

Topics covered: Validation (aka “Validation Functor”, “Validation Applicative”, “Validation Monad”).

涵盖的主题: 验证(又名“验证函子”,“验证适用性”,“验证单子”)

Validations are commonly referred as Validation Applicative because it is commonly used for validation using it’s “ap”(apply) function.

验证通常称为“ 验证适用性”,因为它通常使用其“ ap”(应用)功能进行验证。

Validations are similar to Either Monads and used to work with composing multiple error-throwing functions. But unlike with Either Monad, where we typically use its “chain” method to compose, in Validation Monads, we typically use “ap” method to compose. And unlike either’s “chain” method, where we only collect the 1st error, “ap” method, especially in Validation Monads allows us to collect all the errors in an Array.

验证Either Monads相似,并且用于组合多个错误抛出函数。 但是与Either Monad不同的是,我们通常使用其“链”方法进行撰写,而在Validation Monad中,我们通常使用“ ap”方法进行撰写。 与任何一个“链”方法(我们只收集第一个错误)不同, “ ap”方法(尤其是在Validation Monad中)使我们可以将所有错误收集到Array中

They are typically used in form validation where we may want to show all the errors at the same time.

它们通常用于表单验证中,我们可能希望同时显示所有错误。

Use case: We have a sign up form that validates username, password and email using 3 functions(isUsernameValid, isPwdLengthCorrect and ieEmailValid. We need to show all 1, 2 or 3 errors if they all occur at the same time.

用例:我们有一个注册表单,使用3个函数(isUsernameValid,isPwdLengthCorrect和ieEmailValid)验证用户名,密码和电子邮件。如果它们同时发生,则需要显示所有1、2或3个错误。

OK, let’s see how to implement it using “Validation Applicative”.

好的,让我们看看如何使用“ Validation Applicative”来实现它。

We’ll use data.validation lib from folktalejs because ramda-fantasy doesn’t implement it yet.

因为ramda-fantasy尚未实现它,所以我们将使用民俗故事中的 data.validation库。

Similar to “Either” Monad, it has two constructors: Success and Failure. These are like subclasses that each implement Either’s specs.

与“任何一个” Monad相似,它具有两个构造函数: SuccessFailure 这些就像每个实现Either规范的子类。

Step1: In order to use Validation, all we need to do is to wrap valid values and errors inside Success and Failure constructors (i.e. create instances of those classes).

步骤1:为了使用Validation,我们要做的就是将有效值和错误包装在SuccessFailure构造函数中(即创建这些类的实例)。

const Validation = require('data.validation') //from folktalejsconst Success = Validation.Successconst Failure = Validation.Failureconst R = require('ramda');//Instead Of:function isUsernameValid(a) {    return /^(0|[1-9][0-9]*)$/.test(a) ?           ["Username can't be a number"] : a}//Use:function isUsernameValid(a) {    return /^(0|[1-9][0-9]*)$/.test(a) ?         Failure(["Username can't be a number"]) : Success(a)}

const Validation = require('data.validation') //from folktalejs const Success = Validation.Success const Failure = Validation.Failure const R = require('ramda'); //Instead Of: const R = require('ramda'); //Instead Of: function isUsernameValid(a) { return /^(0|[1-9][0-9]*)$/.test(a) ? ["Username can't be a number"] : a } //Use: function isUsernameValid(a) { return /^(0|[1-9][0-9]*)$/.test(a) ? Failure (["Username can't be a number"]) : Success (a) }

Repeat the process for ALL error throwing validation functions.

对所有错误抛出验证功能重复该过程。

Step 2: Create a dummy function to hold validation success.

步骤2:创建一个虚拟函数以保持验证成功。

const returnSuccess = () => 'success';//simply returns success

const returnSuccess = () => 'success';//simply returns success

Step 3: Use curryN to repeatedly apply “ap”

步骤3:使用curryN重复应用“ ap”

The problem with “ap” is that the left-hand side should be a functor (or a monad) containing function.

“ ap”的问题在于,左侧应该是包含函数的函子(或monad)。

For example, let’s say we want to repeatedly apply “ap” like below. It will only work if monad1 contains a function. And the result of monad1.ap(monad2) i.e. resultingMonad is also a monad with a function so that we can “ap” to monad3.

例如,假设我们要像下面一样重复应用“ ap”。 仅在monad1包含函数的情况下才有效。 和monad1.ap(monad2)的结果,即resultingMonad也有功能的单子,这样我们就可以“AP”,以monad3。

let finalResult = monad1.ap(monad2).ap(monad3)//Can be rewritten as:let resultingMonad = monad1.ap(monad2)let finalResult = resultingMonad.ap(monad3)//will only work if: monad1 has a function and monad1.ap(monad2) results in another monad (resultingMonad) with a function

let finalResult = monad1.ap(monad2).ap(monad3) //Can be rewritten as: let resultingMonad = monad1.ap(monad2) let finalResult = resultingMonad.ap(monad3) //will only work if: monad1 has a function and monad1.ap(monad2) results in another monad (resultingMonad) with a function

Generally speaking, we need 2 monads that has functions in order to apply “ap” twice.

一般而言,我们需要2个具有功能的单子,以便两次应用“ ap”。

In our case, we have 3 functions that we need to apply.

在我们的案例中,我们需要应用3个函数。

Let’s say we did something like below.

假设我们做了以下类似的事情。

Success(returnSuccess)        .ap(isUsernameValid(username)) //works        .ap(isPwdLengthCorrect(pwd))//wont work        .ap(ieEmailValid(email))//wont work

Success(returnSuccess) .ap(isUsernameValid(username)) //works .ap(isPwdLengthCorrect(pwd))//wont work .ap(ieEmailValid(email))//wont work

The above won’t work because Success(returnSuccess).ap(isUsernameValid(username)) will result in a value. And we can no longer continue to do “ap” on 2nd and 3rd function.

上面的方法不起作用,因为Success(returnSuccess).ap(isUsernameValid(username))将产生一个值。 而且我们不能再继续对第二和第三功能执行“ ap”操作。

Enter curryN.

输入curryN。

We can use curryN to keep returning function until it is called “N” number of times.

我们可以使用curryN来保持返回功能,直到被称为“ N”次为止。

So we can simply do:

因此,我们可以简单地执行以下操作:

//3 coz we are calling "ap" 3 times.let success = R.curryN(3, returnSuccess);

//3 coz we are calling "ap" 3 times. let success = R.curryN(3, returnSuccess);

Now, the curried success keeps returning function 3 times.

现在, 成功的成功保持了3次返回功能。

function validateForm(username, pwd, email) {    //3 coz we are calling "ap" 3 times.    let success = R.curryN(3, returnSuccess);    return Success(success)// default; used for 3 "ap"s        .ap(isUsernameValid(username))        .ap(isPwdLengthCorrect(pwd))        .ap(ieEmailValid(email))}

function validateForm(username, pwd, email) { //3 coz we are calling "ap" 3 times. let success = R.curryN(3, returnSuccess); return Success(success)// default; used for 3 "ap"s let success = R.curryN(3, returnSuccess); return Success(success)// default; used for 3 "ap"s .ap(isUsernameValid(username)) let success = R.curryN(3, returnSuccess); return Success(success)// default; used for 3 "ap"s .ap(isPwdLengthCorrect(pwd)) .ap(ieEmailValid(email)) }

Putting it all together:

放在一起:

If you liked the post by clicking on the ? it below and sharing it on Twitter! Thanks for reading! ??

如果您喜欢该帖子,请单击“?”。 并在Twitter上分享! 谢谢阅读! ??

我的其他帖子 (My Other Posts)

LATEST: The Inner workings of the Browser — for JavaScript & Web Developers Use code: INNER15 and get 50% off!

最新消息: 浏览器的内部工作原理-适用于JavaScript和Web开发人员 使用代码:INNER15可获得50%的折扣!

功能编程 (Functional Programming)

  1. JavaScript Is Turing Complete — Explained

    JavaScript正在完善–解释

  2. Functional Programming In JS — With Practical Examples (Part 1)

    JS中的函数式编程—结合实际示例(第1部分)

  3. Functional Programming In JS — With Practical Examples (Part 2)

    JS中的函数式编程—结合实际示例(第2部分)

ES6 (ES6)

  1. 5 JavaScript “Bad” Parts That Are Fixed In ES6

    ES6中修复的5个JavaScript“不良”部分

  2. Is “Class” In ES6 The New “Bad” Part?

    ES6中的“类”是新的“不良”部分吗?

Web包装 (WebPack)

  1. Webpack — The Confusing Parts

    Webpack —令人困惑的部分

  2. Webpack & Hot Module Replacement [HMR] (under-the-hood)

    Webpack和热模块更换[HMR] (在内部)

  3. Webpack’s HMR And React-Hot-Loader — The Missing Manual

    Webpack的HMR和React-Hot-Loader —缺少的手册

Draft.js (Draft.js)

  1. Why Draft.js And Why You Should Contribute

    为什么选择Draft.js以及为什么您应该贡献力量

  2. How Draft.js Represents Rich Text Data

    Draft.js如何表示富文本数据

React And Redux: (React And Redux :)

  1. Step by Step Guide To Building React Redux Apps

    构建React Redux应用程序的逐步指南

  2. A Guide For Building A React Redux CRUD App (3-page app)

    构建React Redux CRUD应用程序指南 (3页应用程序)

  3. Using Middlewares In React Redux Apps

    在React Redux应用程序中使用中间件

  4. Adding A Robust Form Validation To React Redux Apps

    向React Redux应用添加强大的表单验证

  5. Securing React Redux Apps With JWT Tokens

    使用JWT令牌保护React Redux应用程序

  6. Handling Transactional Emails In React Redux Apps

    在React Redux应用程序中处理交易电子邮件

  7. The Anatomy Of A React Redux App

    React Redux应用程序剖析

销售队伍 (Salesforce)

  1. Developing React Redux Apps In Salesforce’s Visualforce

    在Salesforce的Visualforce中开发React Redux应用程序

翻译自: https://www.freecodecamp.org/news/functional-programming-in-js-with-practical-examples-part-2-429d2e8ccc9e/

javascript函数式

javascript函数式_JavaScript中的函数式编程—结合实际示例(第2部分)相关推荐

  1. javascript函数式_JavaScript中的函数式编程—结合实际示例(第1部分)

    javascript函数式 by rajaraodv 通过rajaraodv JavaScript中的函数式编程-结合实际示例(第1部分) (Functional Programming In Jav ...

  2. javascript函数式_JavaScript中的函数式编程原理

    javascript函数式 After a long time learning and working with object-oriented programming, I took a step ...

  3. javascript闭包_JavaScript闭包教程–带有JS闭包示例代码

    javascript闭包 Closures – many of you JavaScript devs have probably heard this term before. When I sta ...

  4. javascript模块_JavaScript中的模块

    javascript模块 JavaScript模块 (JavaScript Modules) One of the key features of programming fundamentals i ...

  5. javascript 解密_Javascript中的AES加密和Java中的解密

    javascript 解密 AES代表高级加密系统,它是一种对称加密算法,很多时候我们需要在客户端加密一些纯文本,例如密码,然后将其发送到服务器,然后由服务器解密以进行进一步处理.AES加密和解密更加 ...

  6. javascript 常量_JavaScript中的常量

    javascript 常量 JavaScript常数 (JavaScript Constants) Before ES15, the only way to declare variables usi ...

  7. javascript运算符_JavaScript中的按位运算符

    javascript运算符 JavaScript按位运算符 (JavaScript Bitwise Operators) A lot of times you come across some str ...

  8. javascript 排序_JavaScript中的排序方法

    javascript 排序 There are tons of sorting algorithms available like bubble sort, merge sort, insertion ...

  9. javascript运算符_JavaScript中!=或!==运算符之间的区别

    javascript运算符 We can perceive the differences between these two operators as the same difference tha ...

最新文章

  1. checkstyle安装使用
  2. Merge Intervals
  3. zoj 2709 Lottery 组合数,概率,贪心 (8-F)
  4. Windows数据类型探幽——千回百转你是谁?(1)
  5. 机器人聊天软件c#_C#制作简易QQ聊天机器人
  6. Python的正则表达式和爬虫
  7. python 打开网页 并填表单_Windows下使用python3 + selenium.webdriver功能实现自动填写网页表单功能...
  8. 比特币base58源码解析_中本聪源码早期版本流出:区块链原名时间链,比特币内置虚拟扑克游戏...
  9. H5网页适配 iPhoneX,就是这么简单
  10. python设计模式9-装饰器模式
  11. 模型加速——卷积通道裁剪的学习笔记
  12. 极域课堂管理系统软件如何取消控制_微缔电子组装业MES系统软件六大功能组成...
  13. 网赚项目:揭秘闲鱼项目,信息差赚钱新手也能日入200+
  14. WIFI手机使用正常电脑使用卡顿解决方案
  15. 基于FBX SDK的FBX模型解析与加载 -(一)
  16. 有一种努力叫“凌晨四点”
  17. 学校计算机教室学生使用记录表,学校学生信息技术教学计划
  18. C++笔记--Linux网络编程(15-0)-socket(供自查,文档说明)
  19. IE6下png背景不透明——张鑫旭博客读书笔记
  20. uiautomator_0

热门文章

  1. ListView控件获取选中项的内容 c# 114867417
  2. sqlserver 2012 不允许保存更改 的解决办法 0108
  3. 爬虫-01-基础入门-字符串基础知识-节符串与字节转换
  4. jquery-绑定事件与解除事件的绑定
  5. 单例测试phpunit
  6. linux安装selenium+chrome+phantomjs
  7. iOS 关于真机和模拟器framework合并
  8. 搭建VS2008下QT开发环境
  9. 还没使用过Web Worker? 推荐一款开源工具Workerize-Loader,让你在webpack项目中轻松使用Web Worker
  10. Docker Compose运行MySQL、Redis服务