Por que o JavaScript é necessário no modo estrito?

O modo estrito é uma parte importante do JavaScript moderno. É esse modo que permite que os desenvolvedores usem sintaxe mais limitada que a padrão.

A semântica do modo estrito é diferente do modo não estrito tradicional, que às vezes é chamado de "modo superficial". Nesse modo, as regras de sintaxe do idioma não são tão rigorosas e, quando ocorrem alguns erros, o sistema não notifica o usuário sobre eles. Ou seja, os erros podem ser ignorados e o código em que são feitos pode ser executado ainda mais. Isso pode levar a resultados inesperados de execução de código.



O modo estrito introduz algumas alterações na semântica do JavaScript. Impede que o sistema feche os olhos para erros, lançando exceções apropriadas. Isso faz com que a execução do programa pare.

Além disso, o modo estrito ajuda a escrever programas nos quais não há deficiências que impedem que os mecanismos JS otimizem o código. Além disso, neste modo, é proibido o uso de elementos de sintaxe que possam obter um significado especial em versões futuras do idioma.

Recursos do uso do modo estrito


O modo estrito pode ser aplicado a funções individuais ou a um script inteiro. Ele não pode ser aplicado apenas a instruções individuais ou a blocos de código entre chaves. Para usar o modo estrito no nível de todo o script, no início do arquivo, antes de qualquer outro comando, você deve colocar o "use strict" ou 'use strict' construção 'use strict' .

Se o projeto tiver alguns scripts que não usam o modo estrito e outros que usam esse modo, pode acontecer que esses scripts sejam mesclados.

Isso levará ao fato de que o código que não se destina a ser executado no modo estrito estará nesse estado quando o sistema tentar executá-lo no modo estrito. O inverso também é possível - o código escrito para o modo estrito entrará no modo não estrito. Portanto, é melhor não misturar scripts "estritos" e "não estritos".

Como já mencionado, o modo estrito pode ser aplicado a funções individuais. Para fazer isso - a construção "use strict" ou 'use strict' deve ser colocada na parte superior do corpo da função, antes de qualquer outro comando. O modo estrito com essa abordagem se aplica a tudo que é colocado no corpo da função, incluindo funções aninhadas.

Por exemplo:

 const strictFunction = ()=>{  'use strict';  const nestedFunction = ()=>{    //        } } 

Nos módulos JavaScript que apareceram no padrão ES2015, o modo estrito é ativado por padrão. Portanto, ao trabalhar com eles, você não precisa incluí-lo explicitamente.

Alterações introduzidas no código JS pelo modo estrito


O modo estrito afeta a sintaxe do código e a maneira como o código se comporta durante a execução do programa. Erros no código são convertidos em exceções. O fato de que no modo silencioso trava silenciosamente no modo estrito causa uma mensagem de erro. É semelhante à maneira como o sistema responde aos erros de sintaxe no modo lax. No modo estrito, o trabalho com variáveis ​​é simplificado, o uso da função eval e do objeto de arguments é fortemente regulamentado, e o trabalho com construções que podem ser implementadas em versões futuras da linguagem é simplificado.

▍ Converter erros silenciosos em exceções


Erros silenciosos são convertidos no modo estrito em exceções. No modo relaxado, o sistema não responde explicitamente a esses erros. No modo estrito, a presença de tais erros leva à inoperabilidade do código.

Portanto, graças a isso, é difícil cometer o erro de declarar acidentalmente uma variável global, pois variáveis ​​e constantes no modo estrito não podem ser declaradas sem o uso das diretivas var , let ou const . Como resultado, a criação de variáveis ​​sem essas diretivas levará à inoperabilidade do programa. Por exemplo, tentar executar o seguinte código lançará uma exceção ReferenceError :

 'use strict'; badVariable = 1; 

Esse código não pode ser executado no modo estrito, pois se o modo estrito fosse desativado, criaria a variável global badVariable . O modo estrito protege o programador de criar inadvertidamente variáveis ​​globais.

Uma tentativa de executar qualquer código que, no modo normal, simplesmente não funcione, agora gera uma exceção. Os erros são considerados quaisquer construções sintáticas incorretas que foram simplesmente ignoradas no modo lax.

Portanto, por exemplo, no modo estrito, você não pode executar operações de atribuição de valor em entidades somente leitura, como arguments , NaN ou eval .

No modo estrito, uma exceção, por exemplo, será lançada nos seguintes casos:

  • uma tentativa de atribuir um valor a uma propriedade somente leitura, como algum tipo de propriedade global regravável;
  • uma tentativa de escrever um valor para uma propriedade que possui apenas um getter;
  • Uma tentativa de escrever algo em uma propriedade de um objeto não extensível.

Aqui estão exemplos de construções de sintaxe que levam a exceções no modo estrito:

 'use strict'; let undefined = 5; let Infinity = 5; let obj = {}; Object.defineProperty(obj, 'foo', { value: 1, writable: false }); obj.foo = 1 let obj2 = { get foo() { return 17; } }; obj2.foo = 2 let fixedObj = {}; Object.preventExtensions(fixedObj); fixed.bar= 1; 

Tentar executar esses fragmentos de código no modo estrito lançará uma exceção TypeError . Por exemplo, undefined e Infinity são entidades globais cujos valores não podem ser substituídos, e a propriedade foo do objeto obj não suporta reescrita. A propriedade foo do obj2 tem apenas um getter. O objeto fixedObj tornado não extensível usando o método Object.preventExtensions .

Uma tentativa de excluir uma TypeError não TypeError também resultará em TypeError :

 'use strict'; delete Array.prototype 

O modo estrito proíbe atribuir propriedades com o mesmo nome a um objeto. Como resultado, uma tentativa de executar o seguinte código resultará em um erro de sintaxe:

 'use strict'; let o = { a: 1, a: 2 }; 

O modo estrito requer que os nomes dos parâmetros das funções sejam exclusivos. No modo não estrito, se, por exemplo, dois parâmetros de função tiverem o mesmo nome, one , ao passar a função de argumento, o valor do parâmetro será o que caiu no argumento declarado por último.

No modo estrito, os parâmetros de funções com o mesmo nome são proibidos. Como resultado, uma tentativa de executar o seguinte código resultará em um erro de sintaxe:

 'use strict'; const multiply = (x, x, y) => x*x*y; 

No modo estrito, você não pode usar a notação octal de números, precedendo o número com zero. Isso não está na especificação, mas esse recurso é suportado pelos navegadores.

Esse estado de coisas confunde os desenvolvedores, forçando-os a acreditar que o 0 que antecede o número é simplesmente ignorado, sem muito sentido. No modo estrito, tentar usar um número no início igual a 0 resultará em um erro de sintaxe.

O modo estrito também proíbe o uso de construções que impedem a otimização. O intérprete, antes de executar a otimização do código, precisa saber que a variável é armazenada exatamente onde, de acordo com o intérprete, é armazenada. No modo estrito, coisas que interferem nas otimizações são proibidas.

Um exemplo dessa proibição diz respeito à declaração with . Se você usar esta instrução, isso impedirá que o interpretador JS descubra a qual variável ou a qual propriedade estamos nos referindo, pois é possível que uma entidade com o mesmo nome exista fora e dentro do bloco da instrução with .

Suponha que exista um código como este:

 let x = 1; with (obj) {  x; } 

O intérprete não poderá descobrir se a variável x localizada dentro do bloco with se refere à variável externa x ou à propriedade obj.x do objeto obj .

Como resultado, não está claro exatamente onde o valor x estará localizado na memória. Para se livrar de tais ambiguidades, no modo estrito é proibido o uso da declaração with . Vamos ver o que acontece se você tentar executar o seguinte código no modo estrito:

 'use strict'; let x = 1; with (obj) {  x; } 

O resultado desta tentativa será um erro de sintaxe.

Mesmo no modo estrito, é proibido declarar variáveis ​​no código passado para o método eval .

Por exemplo, no modo normal, um comando no formato eval('let x') resultará na declaração da variável x . Isso permite que os programadores ocultem declarações de variáveis ​​em strings, o que pode levar à substituição das definições das mesmas variáveis ​​fora de eval .

Para evitar isso, no modo estrito, é proibido declarar variáveis ​​no código passadas como uma string para o método eval .

O modo estrito também proíbe a exclusão de variáveis ​​regulares. Como resultado, a tentativa de executar o seguinte código resultará em um erro de sintaxe:

 'use strict'; let x; delete x; 

▍ Proibindo construções de sintaxe incorretas


No modo estrito, arguments proibido o uso incorreto de avaliação e arguments . Esta é uma proibição de todos os tipos de manipulação com eles. Por exemplo, isso é algo como atribuir novos valores a eles, usando seus nomes como nomes de variáveis, funções e parâmetros de funções.

Aqui estão exemplos de uso indevido de avaliação e arguments :

 'use strict'; eval = 1; arguments++; arguments--; ++eval; eval--; let obj = { set p(arguments) { } }; let eval; try { } catch (arguments) { } try { } catch (eval) { } function x(eval) { } function arguments() { } let y = function eval() { }; let eval = ()=>{ }; let f = new Function('arguments', "'use strict'; return 1;"); 

No modo estrito, você não pode criar aliases para o objeto de arguments e definir novos valores de arguments por meio desses aliases.

No modo normal, se o primeiro parâmetro da função for a , a configuração do valor de a no código da função também levará a uma alteração no valor nos arguments[0] . No modo estrito, os arguments sempre conterão a lista de argumentos com os quais a função foi chamada.

Suponha que você tenha o seguinte código:

 const fn = function(a) {  'use strict';  a = 2;  return [a, arguments[0]]; } console.log(fn(1)) 

O console receberá [2,1] . Isso ocorre porque escrever um valor de 2 em a não escreve um valor de 2 em arguments[0] .

PtOtimize o desempenho


No modo estrito, a propriedade arguments.callee não é suportada. No modo normal, ele retorna o nome da função pai da função cuja propriedade callee dos objetos de arguments que estamos examinando.

O suporte a essa propriedade interfere nas otimizações, como funções embutidas, uma vez que o uso de arguments.callee requer a disponibilidade de uma referência a uma função não incorporada ao acessar esta propriedade. No modo estrito, o uso de arguments.callee gera uma exceção TypeError .

No modo estrito, a this nem sempre precisa ser um objeto. Em circunstâncias normais, se this função estiver vinculada, usando call , apply ou bind , a algo que não seja um objeto, a um valor de um tipo primitivo como undefined , null , number ou boolean , esse valor deverá ser um objeto.

Se o contexto this mudar para algo que não é um objeto, um objeto global substituirá. Por exemplo, window . Isso significa que, se você chamar uma função, definindo this como um valor que não é um objeto, em vez desse valor, uma referência ao objeto global será incluída.

Considere um exemplo:

 'use strict'; function fn() {  return this; } console.log(fn() === undefined); console.log(fn.call(2) === 2); console.log(fn.apply(null) === null); console.log(fn.call(undefined) === undefined); console.log(fn.bind(true)() === true); 

Todos os comandos console.log serão emitidos como true , porque no modo estrito o valor this na função não é automaticamente substituído por uma referência ao objeto global se this definido como um valor que não é um objeto.

Changes Alterações relacionadas à segurança


No modo estrito, você não pode tornar públicas as propriedades da função de caller e arguments . O fato é que o caller , por exemplo, pode dar acesso à função que chamou a função cuja propriedade do caller estamos acessando.

O objeto arguments armazena os argumentos passados ​​para a função quando ela foi chamada. Por exemplo, se tivermos uma função fn , isso significa que, por meio de fn.caller você pode acessar a função que chamou a função e, usando fn.arguments pode ver os argumentos passados ​​para fn quando foi chamado.

Esses recursos representam um risco potencial à segurança. Como resultado, o acesso a essas propriedades é proibido no modo estrito.

 function secretFunction() {  'use strict';  secretFunction.caller;  secretFunction.arguments; } function restrictedRunner() {  return secretFunction(); } restrictedRunner(); 

No exemplo anterior, não podemos, no modo estrito, acessar secretFunction.caller e secretFunction.arguments . O fato é que essas propriedades podem ser usadas para obter uma pilha de chamadas de função. Se você tentar executar esse código, uma exceção TypeError será TypeError .

No modo estrito, identificadores que podem ser usados ​​em versões futuras do JavaScript não podem ser usados ​​para nomear variáveis ​​ou propriedades de objetos. Por exemplo, estamos falando dos seguintes identificadores: implements , interface , let , package , private , protected , public , static e yield .

No ES2015 e em versões posteriores do padrão, esses identificadores se tornaram palavras reservadas. E eles não podem ser usados ​​para nomear variáveis ​​ou propriedades no modo estrito.

Sumário


O modo estrito é um padrão que existe há muitos anos. Goza de suporte extremamente amplo ao navegador. Problemas com o código de modo estrito podem ocorrer apenas em navegadores mais antigos, como o Internet Explorer.

Navegadores modernos não devem ter dificuldades com o modo JavaScript estrito. Como resultado, podemos dizer que esse modo deve ser usado para evitar erros "silenciosos" e aumentar a segurança do aplicativo. Erros silenciosos são convertidos em exceções que impedem a execução de programas e, em termos de melhoria da segurança, por exemplo, podem ser observados mecanismos de modo estrito que restringem a avaliação e impedem o acesso à pilha de chamadas de função. Além disso, o uso do modo estrito facilita a otimização do código do mecanismo JS e força o programador a manipular cuidadosamente palavras reservadas que podem ser usadas em versões futuras do JavaScript.

Caros leitores! Você usa o modo estrito ao escrever o código JS para seus projetos?


Source: https://habr.com/ru/post/pt477284/


All Articles