Закрытие: эквивалент ключевого слова PHP "use" или списка захвата С++ в Javascript или языке транспилятора
в PHP у нас есть аккуратное ключевое слово use
, позволяющее использовать "внешние" переменные при использовании закрытий, например:
$tax = 10;
$totalPrice = function ($quantity, $price) use ($tax){ //mandatory 'use'
return ($price * $quantity) * ($tax + 1.0);
};
Если мы опустим часть use ($tax)
, она выдаст ошибку, которую мне очень нравится.
Аналогично в С++ 11 мы делаем то же самое, указывая внешние переменные, называемые список захвата, с скобками:
float tax = 10;
auto totalPrice = [tax](int quantity, float price){ //mandatory []
return (price*quantity) * (tax + 1.0);
};
Как и в php, он выдаст ошибку, если список захвата опущен.
В Javascript у нас нет эквивалента этого ключевого слова use
(или С++ []), мы просто делаем:
var tax = 10;
var totalPrice = function (quantity, price){ //no need for 'use' or similar
return (price * quantity) * (tax + 1.0); //tax is usable here :(
};
Мне не нравится эта свобода, я предпочитаю указывать переменные, которые будут доступны функции закрытия или получить ошибку в противном случае по причинам, выходящим за рамки этого вопроса.
Итак, мне было интересно, есть ли специальное ключевое слово или оператор для этого в ES6, или на любом языке, который переводит на javascript? (CoffeeScript, TypeScript и т.д.). Если да, на каком языке и в каком синтаксисе?
В идеале я хотел бы обнаружить время трансляции (или раньше), когда переменная не была явно разрешена для использования в закрытии, что очень похоже на PHP/С++.
Заранее спасибо
PS: Пожалуйста, не спрашивайте меня, почему я хочу это на js-подобном языке, эта дискуссия - это еще одна тема.
EDIT: ЛИНТЕР, который выполняет эту проверку, также поможет
Ответы
Ответ 1
К сожалению, поскольку вы можете внедрить ключевое слово use
, не существует в javascript, но для достижения результата, который вы ищете, существует несколько способов.
Итак, это был ваш пример, в котором totalPrice
- это функция, а tax
- глобальная.
// Your example
var tax = 10;
var totalPrice = function (quantity, price) {
return (price * quantity) * (tax + 1.0);
};
var price = totalPrice(1, 1);
console.log ("Price YE is : " + price);
Поэтому я думаю, что, вероятно, решение, которое симулирует больше ключевого слова use
, состоит в том, чтобы сгенерировать функцию, которая инициализирует tax
в подпункте и возвращает функцию:
// Example 1 return function
function generatePriceCalculator(tax) {
return function(quantity, price) {
if ("undefined" === typeof tax) {
throw "tax is undefined";
}
return (price * quantity) * (tax + 1.0);
};
};
var priceCalculator = generatePriceCalculator(20);
var price1 = priceCalculator(1, 1);
console.log ("Price Example 1 is : " + price1);
Как вы можете видеть, generatePriceCalculator
устанавливает значение для tax
в возвращаемой функции.
Другой вариант - создать внешнюю функцию для вызова внутри закрытия.
// Example 2 function return tax
function getTax() {
return 30;
}
var totalPrice2 = function (quantity, price) {
var tax = getTax();
return (price * quantity) * (tax + 1.0);
};
var price2 = totalPrice2(1, 1);
console.log ("Price Example 2 is : " + price2);
Здесь вы можете увидеть все:
https://jsfiddle.net/jo9yzoke/1/
Ответ 2
В JavaScript нет такого ключевого слова.
В переменных JavaScript доступны все дочерние области, например:
(function() {
var outerVariable = true;
(function() {
console.log(typeof outerVariable); // boolean
(function() {
console.log(typeof outerVariable); // boolean
}())
}());
}());
Однако вы не можете получить доступ к переменным, которые были определены в отдельной, не родительской области, например:
(function() {
var someVariable = true;
}());
(function() {
console.log(typeof someVariable); // undefined
}());
Вот почему вы должны писать код JavaScript таким образом, чтобы у вас всегда был доступ только к необходимым вам переменным. Рассмотрим следующий пример:
(function() {
var math = (function() {
// inner variable
var PI = 3.141592653589793;
// inner function
function multiply(...args) {
return args.reduce((a, b)=> a * b);
}
// outer functions
return {
circleArea: function circleArea(r) {
return multiply(r, r, PI);
},
circumference: function circumference(r) {
return multiply(2, PI, r);
}
};
}());
console.log(math.circleArea(5)); // 78.53981633974483
console.log(math.circumference(10)); // 62.83185307179586
console.log(typeof PI); // "undefined"
console.log(typeof multiply); // "undefined"
}());
Внутри IIFE, который создает объект math
, вы можете использовать переменную PI
и multiply
. IIFE возвращает две функции, которые могут получить доступ к PI
и multiply
тоже, потому что они все еще находятся внутри этого IIFE. Вы можете вызвать math.circleArea()
и math.circumference()
извне этого IIFE, но вы можете получить доступ к PI
или multiply
— они undefined
в этой области.
См. также:
Ответ 3
Прежде всего: JS - это не PHP, а С++ и никогда не будет.
use()
не для JS. У вас есть много возможных примеров, чтобы сделать то, что вам нужно, это довольно гибкий язык. Кроме тех, что были в предыдущих ответах, я хотел бы поделиться еще одним примером:
var tax = 'improper';
var priceFactory = function(tax) {
// private `tax` variable for this scope
var tax = tax;
// or a nightmare to check it
// var tax = 'number' == typeof tax && tax || function() { throw "No tax given"; }();
return function(quantity, price) {
return (price * quantity) * (1 + tax / 100);
}
};
var price = new priceFactory(10); // 10%
var totalPrice = price(1, 100)
Ответ 4
Вот еще один альтернативный подход. Если ваша цель в поиске эквивалента use
в javascript заключается в написании более чистого кода, вы можете взглянуть на window.variablename
. Переменные в глобальной области видимости в javascript являются неявно свойствами объекта window. Например, вы можете написать:
var window.tax = 10;
var totalPrice = function (quantity, price){ //no need for 'use' or similar
return (price * quantity) * (window.tax + 1.0); //tax is usable here :(
};
Это явно указывает кому-то, читающему код, что tax
, на который ссылается функция, является tax
частью глобальной области (а именно window.tax
).
Ответ 5
Я не думаю, что JS когда-нибудь предложит вам то, что вы хотите. PHP имеет строгую сферу. Если я определяю переменную внутри функции, она ограничивается этой функцией. Аналогично, что-то определенное вне этой функции неявно доступно внутри функции. use
, например global
, просто изменяется, где и когда вы можете использовать переменную внутри определенной области.
JS по умолчанию помещает все в глобальную область. Фактически, это форма странного мира, поскольку вы ограничиваете область видимости переменной внутри функции, которую вы либо должны иметь в качестве аргумента, либо явно limit область для этой переменной
function bob(x) {
// x is implicitly local
y = 1; //global
var z = 2; //local
}
Другими словами, все переменные в JS use
объявляются неявно.
Ответ 6
Вы можете привязать свои внешние переменные к ключевому слову this
вашего закрытия, используя функцию .bind()
:
Метод bind() создает новую функцию, которая при вызове имеет свой это ключевое слово установлено на предоставленное значение, с заданной последовательностью аргументы, предшествующие любому, предоставленному при вызове новой функции.
См
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind