Javascript replace with callback

JavaScript replace with callback – performance question

In JavaScript, you can define a callback handler in regex string replace operations:

str.replace(/str[123]|etc/, replaceCallback); 

Imagine you have a lookup object of strings and replacements.

and this callback function:

var replaceCallback = function(match)

How would you assess the performance of the above callback? Are there solid ways to improve it? Would

return lookup[match] || match; 

lead to opportunities for the JS compiler to optimize, or is it all the same thing?

Best Solution

+1 to Annie about perf benchmarks.

return lookup[match] || match; 

Not only is it just a single retrieval of the property (rather than — barring optimization — two, as in your earlier examples), but it’s also shorter and (this is not always true of shorter code) clearer to any half-experienced JavaScript coder. It will tend to throw novices a bit, but one of the first things you want to teach novices is how the special (and excellent) || and && work in JavaScript, so.

It also works around a couple of (very) edge cases in some implementations. (Example: ‘toString’ in <> should be true [all objects inherit toString from the Object prototype], but it’s false in Microsoft’s JScript.)

Regarding optimizing: Barring the glaringly obvious (don’t make your loop condition a function that has to go count things if it can be an invariant, avoid duplicating lookups unnecessarily), even absent the general discussion of whether it’s worth worrying about this stuff before you see a problem (sometimes called «premature optimization»), it’s especially true of JavaScript for the general web. Different micro-optimizations have different results in different implementations, sometimes conflicting results («A» being better in Internet Explorer but much worse in FireFox, and the converse). Mostly it’s a matter of wait until you see a specific problem, then address that specific problem.

I prefer simplicity and clarity, unless I have a strong reason to believe that something clunkier is going to give me a measurable, real-world improvement.

Javascript – How to validate an email address in JavaScript

Using regular expressions is probably the best way. You can see a bunch of tests here (taken from chromium)

function validateEmail(email) < const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[8\.1\.1\.6\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]))$/; return re.test(String(email).toLowerCase()); > 

Here’s the example of regular expresion that accepts unicode:

But keep in mind that one should not rely only upon JavaScript validation. JavaScript can easily be disabled. This should be validated on the server side as well.

Here’s an example of the above in action:

function validateEmail(email) < const re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[2\.1\.4\.7\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]))$/; return re.test(email); > function validate() < const $result = $("#result"); const email = $("#email").val(); $result.text(""); if (validateEmail(email)) < $result.text(email + " is valid :)"); $result.css("color", "green"); >else < $result.text(email + " is not valid :("); $result.css("color", "red"); >return false; > $("#email").on("input", validate);
Javascript – How do JavaScript closures work

A closure is a pairing of:

Читайте также:  Float box left html

A lexical environment is part of every execution context (stack frame) and is a map between identifiers (ie. local variable names) and values.

Every function in JavaScript maintains a reference to its outer lexical environment. This reference is used to configure the execution context created when a function is invoked. This reference enables code inside the function to «see» variables declared outside the function, regardless of when and where the function is called.

If a function was called by a function, which in turn was called by another function, then a chain of references to outer lexical environments is created. This chain is called the scope chain.

In the following code, inner forms a closure with the lexical environment of the execution context created when foo is invoked, closing over variable secret :

function foo() < const secret = Math.trunc(Math.random()*100) return function inner() < console.log(`The secret number is $.`) > > const f = foo() // `secret` is not directly accessible from outside `foo` f() // The only way to retrieve `secret`, is to invoke `f`

In other words: in JavaScript, functions carry a reference to a private «box of state», to which only they (and any other functions declared within the same lexical environment) have access. This box of the state is invisible to the caller of the function, delivering an excellent mechanism for data-hiding and encapsulation.

And remember: functions in JavaScript can be passed around like variables (first-class functions), meaning these pairings of functionality and state can be passed around your program: similar to how you might pass an instance of a class around in C++.

If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier.

So, if you want a function to always have access to a private piece of state, you can use a closure.

. and frequently we do want to associate the state with a function. For example, in Java or C++, when you add a private instance variable and a method to a class, you are associating state with functionality.

In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed. In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. In this way, in the code above, secret remains available to the function object inner , after it has been returned from foo .

Uses of Closures

Closures are useful whenever you need a private state associated with a function. This is a very common scenario — and remember: JavaScript did not have a class syntax until 2015, and it still does not have a private field syntax. Closures meet this need.

Private Instance Variables

In the following code, the function toString closes over the details of the car.

function Car(manufacturer, model, year, color) < return < toString() < return `$$ ($, $)` > > > const car = new Car('Aston Martin','V8 Vantage','2012','Quantum Silver') console.log(car.toString())

Functional Programming

In the following code, the function inner closes over both fn and args .

function curry(fn) < const args = [] return function inner(arg) < if(args.length === fn.length) return fn(. args) args.push(arg) return inner >> function add(a, b) < return a + b >const curriedAdd = curry(add) console.log(curriedAdd(2)(3)()) // 5

Event-Oriented Programming

In the following code, function onClick closes over variable BACKGROUND_COLOR .

const $ = document.querySelector.bind(document) const BACKGROUND_COLOR = 'rgba(200,200,242,1)' function onClick() < $('body').style.background = BACKGROUND_COLOR >$('button').addEventListener('click', onClick)

Modularization

In the following example, all the implementation details are hidden inside an immediately executed function expression. The functions tick and toString close over the private state and functions they need to complete their work. Closures have enabled us to modularise and encapsulate our code.

let namespace = <>; (function foo(n) < let numbers = [] function format(n) < return Math.trunc(n) >function tick() < numbers.push(Math.random() * 100) >function toString() < return numbers.map(format) >n.counter = < tick, toString >>(namespace)) const counter = namespace.counter counter.tick() counter.tick() console.log(counter.toString())

Examples

Example 1

This example shows that the local variables are not copied in the closure: the closure maintains a reference to the original variables themselves. It is as though the stack-frame stays alive in memory even after the outer function exits.

function foo() < let x = 42 let inner = function() < console.log(x) >x = x+1 return inner > var f = foo() f() // logs 43

Example 2

In the following code, three methods log , increment , and update all close over the same lexical environment.

Читайте также:  Программа блок схем php

And every time createObject is called, a new execution context (stack frame) is created and a completely new variable x , and a new set of functions ( log etc.) are created, that close over this new variable.

function createObject() < let x = 42; return < log() < console.log(x) >, increment() < x++ >, update(value) < x = value >> > const o = createObject() o.increment() o.log() // 43 o.update(5) o.log() // 5 const p = createObject() p.log() // 42

Example 3

If you are using variables declared using var , be careful you understand which variable you are closing over. Variables declared using var are hoisted. This is much less of a problem in modern JavaScript due to the introduction of let and const .

In the following code, each time around the loop, a new function inner is created, which closes over i . But because var i is hoisted outside the loop, all of these inner functions close over the same variable, meaning that the final value of i (3) is printed, three times.

function foo() < var result = [] for (var i = 0; i < 3; i++) < result.push(function inner() < console.log(i) >) > return result > const result = foo() // The following will print `3`, three times. for (var i = 0; i

Final points:

  • Whenever a function is declared in JavaScript closure is created.
  • Returning a function from inside another function is the classic example of closure, because the state inside the outer function is implicitly available to the returned inner function, even after the outer function has completed execution.
  • Whenever you use eval() inside a function, a closure is used. The text you eval can reference local variables of the function, and in the non-strict mode, you can even create new local variables by using eval(‘var foo = …’) .
  • When you use new Function(…) (the Function constructor) inside a function, it does not close over its lexical environment: it closes over the global context instead. The new function cannot reference the local variables of the outer function.
  • A closure in JavaScript is like keeping a reference (NOT a copy) to the scope at the point of function declaration, which in turn keeps a reference to its outer scope, and so on, all the way to the global object at the top of the scope chain.
  • A closure is created when a function is declared; this closure is used to configure the execution context when the function is invoked.
  • A new set of local variables is created every time a function is called.
Читайте также:  Convert utf to ascii python
  • Douglas Crockford’s simulated private attributes and private methods for an object, using closures.
  • A great explanation of how closures can cause memory leaks in IE if you are not careful.
  • MDN documentation on JavaScript Closures.
Related Question

Источник

Коллбэк в методе replace в регулярках JavaScript

Метод replace вторым параметром может принимать не только строку, но и функцию-коллбэк, которая применится для каждого найденного совпадения. Каждая подстрока, которую нашла регулярка, заменится на то, что вернет эта функция именно для этой подстроки.

В эту функцию можно передавать параметры: в первый параметр положится найденная строка, во второй параметр — первый карман, в третий параметр — второй карман и так далее — можно делать сколько параметров, сколько карманов в регулярном выражении.

В предпоследний параметр положится позиция найденного совпадения, а в последний — вся строка, по которой делается поиск.

Как это все работает — разберем на практических примерах.

Пример

Пусть дана строка с числами:

Давайте заменим эти числа на их квадраты. Для начала давайте просто выведем наши числа по очереди в консоль в функции-коллбэке:

Наш код выведет сначала ‘2’ , потом ‘3’ , ‘4’ и ‘5’ . То есть в переменную match последовательно попадают те строки, которые нашла регулярка.

Давайте решим задачу до конца — будем возводить match в квадрат и возвращать его с помощью return . Получится, что для найденной двойки вернется 4 и двойка заменится на эту четверку, для найденной тройки вернется 9 и тройка заменится на эту девятку — и так далее:

Пример

Пусть теперь в строке даны конструкции вида ‘2+3=’ :

Давайте сделаем так, чтобы после равно вставились суммы соответствующих чисел. То есть наша строка должна превратиться в следующую:

Для решения задачи давайте опять поэкспериментируем — разложим первое и второе слагаемые по отдельным карманам:

А теперь окончательно решим задачу: для каждой найденной подстроки просуммируем первый и второй карманы, возьмем нулевой карман (найденную строку, например ‘2+3=’ ), добавим к нему результат и вернем все это через return :

Практические задачи

Найдите числа, стоящие в скобках и увеличьте их в два раза. То есть из нашей строки должна получится следующая:

Найдите все числа и переверните их цифры в обратном порядке. То есть из нашей строки должна получится следующая:

Найдите все даты и преобразуйте их в другой формат так, чтобы получилась следующая строка:

Источник

Оцените статью