2016-01-10 11 views
11

in PHP abbiamo il use parola chiave ordinata per consentire l'utilizzo di variabili 'esterne' quando si utilizzano le chiusure, come la seguente:Chiusure: Equivalente di PHP "uso" parola chiave o un elenco di acquisizione C++ in Javascript o una lingua transpiler

$tax = 10; 
$totalPrice = function ($quantity, $price) use ($tax){ //mandatory 'use' 
    return ($price * $quantity) * ($tax + 1.0); 
}; 

Se omettiamo la parte use ($tax), si genera un errore, che mi piace molto.

Allo stesso modo in C++ 11, noi facciamo lo stesso, specificando le variabili esterne, chiamato capture list, con staffe:

float tax = 10; 
auto totalPrice = [tax](int quantity, float price){ //mandatory [] 
    return (price*quantity) * (tax + 1.0); 
}; 

Come in PHP, esso genera un errore se la lista di cattura viene omesso.

in JavaScript, che non hanno un equivalente a questo use parola chiave (o C++ []), dobbiamo solo fare:

var tax = 10; 
var totalPrice = function (quantity, price){ //no need for 'use' or similar 
    return (price * quantity) * (tax + 1.0); //tax is usable here :(
}; 

non mi piace molto che la libertà, preferisco fortemente specificare le variabili che saranno accessibili dalla funzione di chiusura o otterranno un errore in altro modo, per ragioni che esulano dall'ambito di questa domanda.

Quindi, mi chiedevo, c'è una parola chiave o un operatore speciale per questo in ES6, o in qualsiasi lingua che traspone in javascript? (CoffeeScript, TypeScript, ecc.) In tal caso, in quale lingua e qual è la sintassi?

Idealmente mi piacerebbe rilevare in tempo di transpilation (o prima), quando una variabile non è stata esplicitamente 'autorizzata' per essere utilizzata in una chiusura, proprio come PHP/C++.

Grazie in anticipo

PS: Per favore non mi chiedono perché voglio che questo in un linguaggio JS-come, che il dibattito è un altro argomento.

EDIT: Un linter che esegue questo controllo aiuterebbe anche

+4

__Perché si desidera questo in JS? __ – Rayon

+0

Non penso che ci sia un traspiatore che potrebbe farlo. Dovrebbe gestire l'ambito di queste funzioni e questo potrebbe benissimo infrangere il codice. Sarebbe un affare molto schizzinoso. Penso che la cosa migliore sarebbe avere un linter che ti avvisa delle tue attuali chiusure. – MinusFour

+0

@MinusFour un linter o simili sarebbe fantastico, ne sai uno che controlla questo caso particolare? –

risposta

0

non credo JS potrà mai offrire ciò che si desidera. PHP ha un ambito rigoroso. Se definisco una variabile all'interno di una funzione, è limitata a quella funzione. Allo stesso modo, qualcosa definito al di fuori di quella funzione non è implicitamente disponibile all'interno della funzione. use, come global cambia semplicemente dove e quando è possibile utilizzare una variabile all'interno di un ambito specifico.

JS inserisce tutto nello scope globale per impostazione predefinita. In realtà, è una forma di mondo bizarro, nel senso che si limita la portata di una variabile che all'interno di una funzione si sia avere come argomento o esplicitamente limite lo scopo di quella variabile

function bob(x) { 
    // x is implicitly local 
    y = 1; //global 
    var z = 2; //local 
} 

In altre parole , tutte le variabili in JS sono dichiarate implicitamente use.

+0

A destra, javascript non può farlo, quindi mi aspettavo una soluzione in transpiler/linter come la domanda dice. Grazie per la risposta –

+0

Non definire variabili globali omettendo la parola chiave 'var'. È una cattiva pratica e non funziona in modalità rigorosa. –

+0

@Gothdo Questo è solo un esempio. Non sto affermando che è una buona pratica. – Machavity

3

Purtroppo come potete immaginare la parola chiave use non esiste in javascript ma per ottenere il risultato che state cercando ci sono diversi modi.

Quindi questo è stato il tuo esempio in cui totalPrice è una funzione e tax è globale.

// 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); 

Quindi penso che probabilmente la soluzione che simula più la parola use è quello di generare una funzione che inizializzare tax in un ambito sub e restituire una funzione:

// 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); 

Come si può vedere generatePriceCalculator sta impostando il valore per tax nella funzione che restituisce.

Un'altra opzione è generare una funzione esterna da chiamare all'interno della chiusura.

// 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); 

È possibile vedere tutti loro qui:

https://jsfiddle.net/jo9yzoke/1/

+0

Grazie per la risposta. Sfortunatamente non impedisce/avverte l'uso di Vars esterni all'interno della chiusura. Penso che sarebbe possibile solo con un linguaggio di transpiler o un linter, mi aspettavo quel tipo di risposta. –

2

Non esiste una parola chiave in JavaScript.

In variabili JavaScript sono a disposizione di tutti i bambini ambiti, ad esempio:

(function() { 
    var outerVariable = true; 
    (function() { 
    console.log(typeof outerVariable); // boolean 
    (function() { 
     console.log(typeof outerVariable); // boolean 
    }()) 
    }()); 
}()); 

Tuttavia, non è possibile accedere alle variabili che è stato definito in un ambito, non-genitore separato, ad esempio:

(function() { 
    var someVariable = true; 
}()); 
(function() { 
    console.log(typeof someVariable); // undefined 
}()); 

Questo è il motivo per cui si dovrebbe scrivere il codice JavaScript in modo tale da avere sempre accesso solo alle variabili di cui avete bisogno. Considerare seguente esempio:

(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" 
}()); 

All'interno del IIFE che crea l'oggetto math, è possibile utilizzare PI variabile e la funzione multiply. L'IIFE restituisce due funzioni, che possono accedere anche a PI e multiply, perché sono ancora all'interno di questo IIFE. Puoi chiamare math.circleArea() e math.circumference() dall'esterno di questa IFA, ma puoi accedere a PI o multiply — in questo ambito sono undefined.

Consulta anche:

+0

Grazie per la risposta, so tutto questo sulle chiusure, purtroppo questo non risolve il mio problema. Se non è possibile con javascript, mi aspettavo una soluzione con transpiler/linter –

+0

@EdgarVillegasAlvarado Non c'è soluzione a questo a causa di come funziona JavaScript. "JS non è né PHP né C++ e non lo sarà mai." Non puoi scrivere il tuo JavaScript nello stesso modo in cui scrivi PHP o C++. –

+0

Ecco perché ho menzionato il linguaggio del transpiler. Se non è possibile in JS mi aspettavo una soluzione con il linguaggio del transpiler, che è teoricamente possibile. –

0

Si potrebbe legare le variabili esterne al this parola chiave del vostro chiusura, utilizzando la funzione .bind():

Il bind() metodo create s una nuova funzione che, quando chiamata, ha la sua questa parola chiave impostata sul valore fornito, con una data sequenza di argomenti precedente a quella fornita quando viene chiamata la nuova funzione.

Vedi https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

+1

Questo non ti impedisce di utilizzare variabili globali all'interno di una chiusura. –

2

Prima di tutto: JS non è né PHP C++ e di solito mai essere.

use() non è per JS. Hai un sacco di possibili esempi per fare ciò che ti serve, è un linguaggio abbastanza flessibile. Ad eccezione di quelli nelle risposte precedenti, mi piacerebbe condividere un altro esempio:

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) 
+0

Grazie per la risposta. Conosco tutto questo, ho esperienza con JS. Sfortunatamente questo non risolve il mio problema. Se non è possibile con javascript, mi aspettavo una soluzione con transpiler/linter. –

1

Ecco un altro approccio alternativo. Se il tuo obiettivo nella ricerca di un equivalente di use in javascript è quello di scrivere il codice più pulito, si potrebbe voler dare un'occhiata a window.variablename. Le variabili nell'ambito globale in javascript sono implicitamente proprietà dell'oggetto window. Così, per esempio, si potrebbe scrivere:

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 :(
}; 

Ciò rende esplicitamente chiaro a qualcuno la lettura del codice, che tax riferimento nella funzione è la tax che fa parte della portata globale (vale a dire window.tax).

+0

Sebbene questo non risolva il mio problema, per i miei scopi è una buona idea che le variabili esterne siano usate attraverso un oggetto intermedio (penso che la finestra non sia buona, ma potrebbe essere un'altra), mi ha aperto a nuove idee, +1 per te, grazie –

Problemi correlati