Что такое environment в программировании

Environment, scope, and closures — Programming fundamentals

Video may be blocked due to browser extensions. In the article you will find a solution to this problem.

Lesson notes

  • Environment is a somewhat isolated area of code
  • Things created outside of functions, if statements, loops etc. are in the global environment
  • Squiggly brackets < >defined a new local environment
  • The scope of something are the locations where it is accessible. Things in the global environment have global scope. Things in some local environment have local scope

Global vs. Local

Local constants and variables are not visible outside their scope:

const multiplier = (num) =>  const x = 10; return num * x; > console.log(x); // ReferenceError: x is not defined 

But if x is present globally, it is used and inside x doesn’t matter:

const x = 55; const multiplier = (num) =>  const x = 10; return num * x; > console.log(x); // 55 

Local environment has access to the outside environment:

let a = 0; const changer = () =>  a++; > console.log(a); // 0 changer(); console.log(a); // 1 

The function actually does something only when it’s called, not when it’s defined, so at first a is 0 , but after changer is called, a becomes 1 .

Lexical scope

JavaScript is trying to find the value in the current environment. If the value is not found, JavaScript goes outside, one level at a time, until it finds the value or realizes it cannot be found anywhere.

let a = 7; let b = 10; const multiplier = () =>  let a = 5; return a * b; > multiplier(); // 50 

Here, in the a * b expression multiplier function uses local a (because it’s found locally), and outside b (because it wasn’t found locally).

Closures

const createPrinter = () =>  const name = "King"; const printName = () =>  console.log(name); > return printName; > const myPrinter = createPrinter(); myPrinter(); // King 

myPrinter is a function, that was returned by createPrinter . Even though the call to createPrinter is over and name constant doesn’t exist anymore, the value is remembered in the myPrinter .

This is a closure: a combination of a function and the environment where it was declared.

Optional reading

Lesson transcript

Let’s talk about the environment. The planet is big, but we all share it. If you build a chemical plant, it’s a good idea to somehow isolate it from the outside world, so that the inside stuff stays inside. You can say this building has its own environment, local environment. Isolated from the outside global environment.

Your program has a similar structure for similar reasons. Things you create outside of everything, outside of functions, if statements, loops, and other code blocks, is located in the global environment.

const age = 29; const multiplier = (num) =>  const x = 10; return num * x; > let result = true; 

Here age constant, multiplier function and result variable are all in the global environment. These things are said to have «global scope». Scope means «the locations where the thing is accessible».

Inside of multiplier function, there is a constant named x . Since it’s inside of a code block, it’s a local constant, not a global one. So it’s only visible inside that function, but not outside. It has local scope.

There is another locally scoped thing in the multiplier function — the num argument. It’s not defined as clearly as constants or variables, but it behaves more or less like a local variable.

We can’t access x from outside, it’s like it doesn’t exist there:

const multiplier = (num) =>  const x = 10; return num * x; > console.log(x); // ReferenceError: x is not defined 

console.log is called in the global environment, and x is not defined in the global environment. So we get a Reference Error.

const x = 55; const multiplier = (num) =>  const x = 10; return num * x; > console.log(x); // 55 

There is a global x now, and its value is being printed, but the local x inside the multiplier function is still only visible inside that function. Those two x ‘s have nothing to do with each other, they are in different environments. They don’t clash together even though they have the same name.

Any code block surrounded by squiggly brackets creates a local environment. Here is an example with an if block:

let a = 0; if (a === 0)  const local = 10; > console.log(local); 

Same goes for while and for loops.

Okay, local is not visible outside. But global is visible everywhere. Even inside something? Yes!

let a = 0; const changer = () =>  a++; > console.log(a); // 0 changer(); console.log(a); // 1 

This global variable a is changed inside the changer function. The function actually does something only when it’s called, not when it’s defined, so at first a is 0 , but after changer is called, a becomes 1 .

While it’s tempting to put everything into one global scope and forget about the complexities of having isolated environments, this is a terrible idea. Global variables make your code very, very fragile. Basically, everything can break everything. So, avoid the global scope, store your stuff where it belongs.

Take a look at this program:

let a = 7; let b = 10; const multiplier = () =>  let a = 5; return a * b; > multiplier(); // 50 

The multiplier function returns the product of a and b . a is defined inside, but not b .

When trying to resolve a * b JavaScript looks for the values of a and b . It starts looking locally and goes outside, one scope at a time until it finds the thing or realizes it cannot be found.

So, in this example, JavaScript starts by looking for a inside the local scope — inside the multiplier function. It finds the value right away and proceeds to b . It’s unable to find the value of b in the local scope, so it goes to the outside scope. There it can find b — it’s 10. So, a * b is resolved to 5 * 10 and then to 50 .

This whole piece of code could’ve been inside of another function inside of yet another function. And if b wasn’t found here, JavaScript would’ve kept going outwards, layer by layer, looking for b .

Notice that a = 7 didn’t affect the calculation. a was found inside, so the outside a doesn’t matter.

This is called lexical scoping. The scope of any thing is defined by its location within the code. And nested blocks have access to their outer scopes.

Most programming languages have a notion of scope or environment, and in most languages this mechanism allows closures to exist. A closure is just a fancy name for a function that remembers the outside things that are used inside.

Before we continue, let’s remember how functions are created and used:

f is a pretty useless function, it always returns 0. This whole thing consists of two things: a constant, and a function itself.

It’s important to remember that those two things are separate. First, there is a constant named f . Its value could’ve been a number or a string. But in this case its value is a function.

We used an analogy in the previous lessons: constants are like pieces of paper: name on one side, the value on the other side. This f is, therefore, a piece of paper with an f on one side and the description of the running function on the other side.

When you call this function like this:

. a new box is created, based on the description on that piece of paper.

Okay, back to closures. Consider the following code:

const createPrinter = () =>  const name = "King"; const printName = () =>  console.log(name); > return printName; > const myPrinter = createPrinter(); myPrinter(); // King 

Function createPrinter creates a constant name and then a function called printName . Both of them are local to the createPrinter function, and only accessible from inside of createPrinter .

printName has no local things on its own, but it has access to the enclosing scope, the outside area where name is defined.

Then the createPrinter function returns the printName function. Remember, function definitions are descriptions of the running functions, just pieces of information like numbers or strings. So we can return a function definition like we can return a number.

In the outside scope, we create a constant myPrinter and set its value to whatever createPrinter returns. It returns a function, so now myPrinter is a function. Call it and «King» is printed.

Here is the weird thing: this name constant was created inside the createPrinter function. That function was called and finished. As we know, when the function finishes working it no longer exists. That magic box disappears with everything inside.

BUT it returned another function, and that another function somehow remembered the name constant. So when we call myPrinter it prints «King», the value it remembered even though the scope where it was defined doesn’t exist anymore.

This function that was returned from createPrinter is called a closure. A closure is a combination of a function and the environment where it was declared.

This might seem like a JavaScript party trick, but closures, when used right, can allow for nicer, clearer and more readable code. And the whole idea of returning functions the same way your return numbers or strings gives a lot of power and flexibility.

You’ll see these ideas used a lot in programming, and we’ll explore their power in the next courses.

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

Источник

Забытое слово: environment

Давным-давно, когда компьютеры были большими, а программы маленькими, использовалось такое важное понятие, как Environment. Этот хороший термин уже утратил зарезервированный смысл, но не потерял своей актуальности. В связи с широким использованием виртуализации, информация об операционном окружении стала предметом обсуждения и в чем-то даже спортивного интереса среди программистов. Поучаствовать в этом мы решили с «железным» аргументом — инструкцией CPUID.

Почему так? Дело в том, что кроме стандартных и расширенных функций в CPUID реализованы виртуальные функции, за выполнение которых отвечает гипервизор хост-системы. В этом случае результатом запроса get hypervisor information может быть одна из сигнатур, однозначно определяющих операционную среду. В зависимости от реализации нам могут быть доступны следующие сигнатуры (список неполный):

image

Для того чтобы идентифицировать особенности виртуальной среды, реализованной Oracle VirtualBox, решено было на базе ранее написанного примера UEFIInfo (в англоязычной интерпретации — Brief Sysinfo Utility), предназначенного для работы в режиме EFI Byte Code с 32-битными и 64-битными реализациями UEFI BIOS, написать рабочий софт идентифицирующий этот самый environment. (Кое-что о наших экспериментах с EBC опубликовано здесь, на Хабре. См., например, заметку «EFI Byte Code и операции с памятью»)

Почему UEFI? Потому что эксперименты с firmware — это своего рода «чистая комната», свободная от культурных наслоений программного обеспечения. Имея на руках отлаженный алгоритм несложно выйти на реализацию подобного программного обеспечения для Linux или Windows.

Исходный код утилиты UEFIInfo v0.02 на языке ассемблера решено было выложить для всеобщего обозрения. Для привлечения внимания размещаем скриншот ее выполнения в виртуальной среде Oracle VirtualBox, отягощенной влиянием открытой реализации TianoCore:

image

Источник

Читайте также:  Middle это в программировании
Оцените статью