今天,在JavaScript手册翻译的第七部分中,我们将讨论严格模式下的代码执行,this关键字的功能,事件,模块以及数学计算。 在这里,我们将讨论使用计时器和异步编程的主题。
→
第1部分:第一个程序,语言功能,标准→
第2部分:代码样式和程序结构→
第3部分:变量,数据类型,表达式,对象→
第4部分:功能→
第5部分:数组和循环→
第6部分:异常,分号,通配符文字→
第7部分:严格模式,此关键字,事件,模块,数学计算→
第8部分:ES6功能概述→
第9部分:ES7,ES8和ES9标准概述
严格模式
严格模式出现在ES5标准中。 在这种模式下,语言的语义发生了变化,旨在改善JavaScript的行为,从而导致这种模式下的代码行为与正常行为不同。 实际上,我们正在谈论的事实是,在这种模式下,由于兼容性原因而消除了该语言的缺点,模棱两可和过时的功能。
strict启用严格模式
为了在某些代码中使用严格模式,必须显式启用它。 也就是说,我们不是在谈论默认使用此模式的事实。 自1996年以来,这种方法将破坏从一开始就存在的基于语言机制的无数现有程序的工作。 实际上,开发JavaScript标准的人员的大量努力专门用于确保兼容性,以便可以在当今的JS引擎上执行基于旧版本标准编写的代码。 可以将这种方法视为JavaScript作为Web开发语言成功的关键之一。
为了启用严格模式,使用了一个特殊的指令,如下所示。
'use strict'
以
"use strict"
的形式编写的指令和使用相同的指令后再使用分号(
'use strict';
和
"use strict";
)可产生相同的效果。 该指令(与引号一样)与该指令一样,以便将某个文件中的所有代码以严格模式执行,放在该文件的开头。
'use strict' const name = 'Flavio' const hello = () => 'hey'
可以在单独功能级别启用严格模式。 为此,必须将相应的指令放在函数体代码的开头。
function hello() { 'use strict' return 'hey' }
如果需要在现有代码库中使用严格模式,并且由于缺乏时间对整个文件的代码进行全面测试而在文件级别将其打开是不切实际的,那么这可能会很有用。
请注意,如果启用了严格模式,则在程序执行期间无法将其关闭。
考虑严格模式的一些功能。
▍打击全局变量的随机初始化
我们已经说过,如果您意外地给未声明的变量分配了某个值,即使您在函数代码中进行了设置,默认情况下也会将该变量设置为全局变量(属于全局对象)。 这可能会导致意外。
例如,以下代码将创建这样的变量。
;(function() { variable = 'hey' })()
执行IIFE后,
variable
将在全局范围内可用。
如果在此功能级别启用了严格模式,则相同的代码将导致错误。
;(function() { 'use strict' variable = 'hey' })()
assignment分配作业中发生的错误
在正常模式下,JavaScript不会报告分配操作期间发生的任何错误。
例如,在JS中,有一个
undefined值,它是语言的原始值之一,由全局对象
undefined
的属性表示。 在常规JS中,这样的命令是完全可能的。
undefined = 1
看起来好像是将单元写入名称为
undefined
的某个变量,但是实际上,这是尝试将新值写入全局对象的属性,顺便说一句,按照标准,该值不能被覆盖。 在正常模式下,尽管可以使用这样的命令,但是它不会导致任何结果-即,
undefined
值将不会更改,并且不会出现错误消息。 在严格模式下,这将导致错误。 为了查看此错误消息,同时确保在正常模式下未覆盖
undefined
值,请在浏览器或Node.js中尝试以下代码。
undefined = 1 console.log('This is '+undefined) ;(() => { 'use strict' undefined = 1 })()
当使用诸如
Infinity
和
NaN
实体以及其他类似实体时,相同的系统行为也是特征。 严格模式可以避免所有这些情况。
在JavaScript中,可以使用
Object.defineProperty()方法设置对象的属性。 特别是,使用此方法可以设置无法更改的属性。
const car = {} Object.defineProperty(car, 'color', { value: 'blue', writable: false }) console.log(car.color) car.color = 'yellow' console.log(car.color)
注意设置
color
属性时使用的
writable: false
属性。
上面的代码在正常模式下执行,既不会导致
color
对象的属性发生变化,也不会导致错误输出。 尝试在严格模式下更改此属性将导致错误。
;(() => { 'use strict' car.color = 'red' })()
吸气剂也是如此。 该代码将执行,但无济于事。
const car = { get color() { return 'blue' } } console.log(car.color) car.color = 'red' console.log(car.color)
在严格模式下尝试执行相同操作将导致错误,报告尝试设置仅具有吸气剂的对象的属性。
;(() => { 'use strict' car.color = 'yellow' } )()
JavaScript具有
Object.preventExtensions()方法,该方法使对象不可扩展,即无法向其添加新属性的对象。 在常规模式下使用此类对象时,将体现出我们上面检查的语言的相同功能。
const car = { color: 'blue' } Object.preventExtensions(car) console.log(car.model) car.model = 'Fiesta' console.log(car.model)
在这里,两次尝试导出
model
对象的属性的尝试都会导致
undefined
值出现在控制台中。 对象中没有这样的属性;在使对象成为不可扩展对象之后尝试创建它不会产生任何结果。 严格模式下的相同操作将导致错误消息。
;(() => { 'use strict' car.owner = 'Flavio' } )()
在同一类动作中,它们不会导致程序员可能期望的任何更改,但也不会导致错误,因此操作会陷入尝试将某些属性分配给原始值的过程。 例如,在正常模式下,这样的代码不会导致错误,但是不会产生任何结果。
let one = 1 one.prop = 2 console.log(one.prop)
严格模式下的相同设置将导致错误消息,指示无法在数字
1
上创建
prop
属性。 以类似的方式,系统在处理其他原始数据类型时会运行。
▍实体删除错误
在正常模式下,如果尝试使用
delete运算符
删除无法删除的对象属性,则
delete
只会返回
false
而所有操作都将失败。
delete Object.prototype
在严格模式下,将在此处生成错误。
▍具有相同名称的函数参数
函数可以具有相同名称的参数,这不会导致错误(尽管这看起来像是创建此类函数的人的错误)。
;(function(a, a, b) { console.log(a, b) })(1, 2, 3)
此代码通常在控制台中显示
2 3
。 在严格模式下,这将导致错误。
顺便说一句,如果在箭头函数的声明期间其参数将具有相同的名称,则在正常模式下,这将导致输出错误消息。
▍八进制值
在普通JavaScript中,可以通过在开头添加
0
来使用八进制值。
;(() => { console.log(010) })()
在这里,八进制数
10
的十进制表示(即
8
将进入控制台。 该数字之前的
0
可以随机放置。 在严格模式下,您不能使用以此格式指定的八进制数字。 但是,如果您需要使用严格模式并使用八进制数字,则可以以
0oXX
格式编写它们。 以下代码还将输出
8
。
;(() => { 'use strict' console.log(0o10) })()
with操作员
在严格模式下,不允许
使用with语句,这可能导致混淆。
以严格模式更改代码的行为不仅限于我们上面讨论的内容。 特别是,在此模式下,this关键字的行为有所不同,我们已经遇到过,现在将更详细地讨论。
此关键字功能
this
(或执行上下文)使您能够描述执行JS代码的环境。 其含义取决于其使用位置以及是否启用严格模式。
strict严格模式下的关键字
在严格模式下,传递给函数的
this
值不会转换为对象。 这种转换不仅需要资源,而且如果在将函数设置为
undefined
或
null
情况下调用函数,也可以使函数访问全局对象。 此行为意味着该函数可能会获得对全局对象的未经授权的访问。 在严格模式下,不执行
this
传递到函数的转换。 为了查看
this
函数在不同模式下的行为之间的区别,请尝试使用
'use strict'
伪指令(不使用它)来尝试这段代码。
;(function() { console.log(this) })()
object对象方法中的this关键字
方法是对象属性中引用的函数。 该函数中的
this
引用此对象。 下面的示例可以说明该语句。
const car = { maker: 'Ford', model: 'Fiesta', drive() { console.log(`Driving a ${this.maker} ${this.model} car!`) } } car.drive()
在这种情况下,我们使用常规函数(而不是箭头1-这很重要),在其中使用的this关键字会自动绑定到包含此函数的对象。
请注意,上面声明对象方法的方法与此类似:
const car = { maker: 'Ford', model: 'Fiesta', drive: function() { console.log(`Driving a ${this.maker} ${this.model} car!`) } }
使用以下构造,也可以观察
this
在对象方法中的相同行为。
const car = { maker: 'Ford', model: 'Fiesta' } car.drive = function() { console.log(`Driving a ${this.maker} ${this.model} car!`) } car.drive()
this关键字this和箭头功能
让我们尝试使用箭头函数作为对象方法来重写以上示例。
const car = { maker: 'Ford', model: 'Fiesta', drive: () => { console.log(`Driving a ${this.maker} ${this.model} car!`) } } car.drive()
如您所见,此处
undefined
显示汽车制造商名称及其型号,而是显示
undefined
值。 事实是,正如我们已经说过的,箭头函数中的该函数包含指向包含该函数的上下文的链接。
此箭头不能绑定到箭头功能,但是您可以
▍绑定此
JavaScript具有
this
绑定的概念。 您可以通过多种方式执行此操作。 例如,在声明函数时,可以使用
bind()
方法将其this关键字绑定到对象。
const car = { maker: 'Ford', model: 'Fiesta' } const drive = function() { console.log(`Driving a ${this.maker} ${this.model} car!`) }.bind(car) drive()
使用相同的方法,可以将另一个对象绑定到一个对象的方法,例如
this
。
const car = { maker: 'Ford', model: 'Fiesta', drive() { console.log(`Driving a ${this.maker} ${this.model} car!`) } } const anotherCar = { maker: 'Audi', model: 'A4' } car.drive.bind(anotherCar)()
此绑定也可以在使用
call()
和
apply()
方法调用函数的阶段进行组织。
const car = { maker: 'Ford', model: 'Fiesta' } const drive = function(kmh) { console.log(`Driving a ${this.maker} ${this.model} car at ${kmh} km/h!`) } drive.call(car, 100)
this
绑定到作为第一个参数传递给这些方法的内容。 这些方法之间的区别在于
apply()
作为第二个参数,采用了将参数传递给函数的数组,而
call()
采用了参数列表。
▍关于浏览器事件处理程序中的此绑定
在事件回调中,
this
指向发生事件的HTML元素。 为了绑定到回调(如
this
,可以使用
bind()
方法。 这是一个示例来说明这一点。
<!DOCTYPE html> <html> <body> <button id="el">Element (this)</button> <button id="win">Window (this</button> <script> const el = document.getElementById("el") el.addEventListener('click', function () { alert(this) </script> </body> </html>
大事记
浏览器中的JavaScript使用事件驱动的编程模型。 这些或其他动作由代码响应事件执行。 在本节中,我们将讨论事件及其处理方法。
例如,事件可以是完成DOM的加载,作为异步请求的结果接收数据,单击页面元素,滚动页面,从键盘输入特定字符。 实际上,在处理许多事件后,页面的JS代码使您能够解决应用程序与用户,页面的元素以及代码工作环境之间的交互中的各种问题。
▍事件处理程序
您可以使用事件处理程序来响应事件,事件处理程序是事件发生时调用的函数。
如果有必要,要处理同一事件,可以注册几个处理程序,如果发生此事件,则将调用它们。 可以以各种方式注册事件处理程序。 考虑三种这样的方法。
▍内置事件处理程序
如今,内置事件处理程序由于其局限性而很少使用。 以前,它们的使用频率更高。 要设置此类事件处理程序,其代码将作为特殊属性添加到元素的HTML标记中。 在下面的示例中,将这样的简单
onclick
事件的处理程序分配给标记为
Button 1
的按钮,该事件在单击按钮时发生。
<!DOCTYPE html> <html> <body> <button onclick="alert('Button 1!')">Button 1</button> <button onclick="doSomething()">Button 2</button> <script> function doSomething(){ const str = 'Button 2!' console.log(str) alert(str) } </script> </body> </html>
Button 2
的HTML代码使用类似的方法,但是它指示一个函数,其功能是响应于按钮单击而执行的。 此代码将给定的字符串输出到控制台,并显示带有相同文本的窗口。
▍将处理程序分配给HTML元素属性
这种分配事件处理程序的方法适用于元素的某个事件仅应具有一个处理程序的情况。 它包括将功能分配给元素的相应属性。
例如,
window
对象具有一个
onload
,该
onload
在加载页面的HTML代码以及它需要的所有其他资源(例如样式和图像)之后调用。 如果为该事件分配处理程序,则在调用它时,可以确保浏览器已加载页面的所有内容,您现在可以通过编程方式使用该内容,而不必担心页面的某些元素尚未加载。
window.onload = () => { alert('Hi!')
处理XHR请求时通常使用此方法。 因此,在建立请求的过程中,您可以为其
onreadystatechange事件指定一个处理程序,该事件在其
readyState
属性更改状态时将被调用。 这是使用此方法从公共API加载JSON数据的示例。
<!DOCTYPE html> <html> <body> <button onclick="loadData()">Start</button> <script> function loadData (){ const xhr = new XMLHttpRequest() const method = 'GET' const url = 'https://jsonplaceholder.typicode.com/todos/1' xhr.open(method, url, true) xhr.onreadystatechange = function () { if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log(xhr.responseText) } } xhr.send() } </script> </body> </html>
要检查是否将处理程序分配给某个事件,可以执行此操作。
if (window.onload){}
▍使用addEventListener()方法
我们已经知道,
addEventListener()
方法是一种用于分配事件处理程序的现代机制。 它允许您为单个事件注册多个处理程序。
window.addEventListener('load', () => {
请注意,IE8浏览器(及其旧版本)不支持
addEventListener()
方法。 它使用类似的
attachEvent()
方法。 如果您的程序应支持过时的浏览器,则应考虑到这一点。
▍关于将事件处理程序分配给各种元素
您可以将事件处理程序连接到
window
对象,以处理“全局”事件,例如按键盘上的按钮。 同时,事件处理程序被分配给各个HTML元素,这些HTML元素可以响应这些元素发生的变化,例如,通过使用鼠标单击它们。 因此,
addEventListener()
方法与
window
对象和普通元素一起使用。
▍事件对象
作为第一个参数,事件处理程序可以采用事件对象
Event
。 该对象的属性集取决于它描述的事件。 例如,这里的代码演示了如何使用
keydown
对象的
keydown
事件来处理键盘击键事件。
<!DOCTYPE html> <html> <body> <script> window.addEventListener('keydown', event => { </script> </body> </html>
如您所见,这里要显示有关控制台按下的键的信息,使用了
key
对象的属性。 这里还使用
type
属性,指示事件的类型。 在此示例中,我们实际上正在使用
KeyboardEvent对象,该对象用于描述与键盘有关的事件。 该对象是
Event对象的后代。 设计用于处理各种事件的对象扩展了标准事件对象的功能。
在同一示例中,
MouseEvent对象用于处理鼠标事件。 在
mousedown
事件处理程序中,我们将事件的类型,按钮号(
button
属性)和单击时指针的坐标(
clientX
和
clientY
)打印到控制台。
DragEvent对象用于处理拖动页面元素时发生的事件。
在其他
Event
对象中可用的
Event
对象的属性中,我们可以提到已经提到的
type
属性和
target
属性,它们指向发生事件的DOM元素。
Event
对象具有方法。 例如,
createEvent()
方法允许您创建新事件。
▍事件处理
考虑以下示例。
<!DOCTYPE html> <html> <head> <style> #container { height: 100px; width: 200px; background-color: blue; } #child { height: 50px; width: 100px; background-color: green; } </style> </head> <body> <div id="container"> <div id="child"> </div> </div> <script> const contDiv = document.getElementById('container') contDiv.addEventListener('click', event => { console.log('container') }) const chDiv = document.getElementById('child') chDiv.addEventListener('click', event => { console.log('child') }) window.addEventListener('click', event => { console.log('window') }) </script> </body> </html>
如果您在浏览器中使用此代码打开页面,请打开控制台,然后在页面的可用区域中先单击鼠标,然后在蓝色矩形中单击鼠标,然后在绿色中单击鼠标,以下内容将进入控制台:
window container window child container window
事件冒泡在这里可以观察到的称为事件冒泡。 即,在子元素处发生的事件扩展到父元素。 这个过程一直持续到事件到达“ top”元素为止。 如果弹出事件沿其传递的元素已定义了相应的处理程序,则将根据事件分发的顺序对其进行调用。
可以使用
stopPropagation()
对象的
stopPropagation()
方法停止事件
stopPropagation()
。 例如,如果有必要在单击
child
元素之后,相应的事件不再传播,则需要重写代码,如下所示,在其中将
click
事件处理程序分配给该代码。
chDiv.addEventListener('click', event => { console.log('child') event.stopPropagation() })
, , — , —
container
, —
child
, .
window container window child
▍
, .
load
load
window
. , , HTML-
body
.
click
.
dblclick
— .
click
dblclick
,
click
, —
dblclick
.
mousedown
,
mousemove
,
mouseup
, . ,
mousemove
, , , . , - , . .
keydown
. , . —
keyup
.
scroll
scroll
window
. , , ,
window.scrollY
.
, ,
mousemove
, .
mousemove
scroll
. - . . «» (throttling),
Lodash . , , , , . .
let cached = null window.addEventListener('mousemove', event => { if (!cached) { setTimeout(() => {
,
mousemove
, 100 .
ES-
ES6 , ES-. , , -, , Node.js, .
, . , , . , , .
Node.js CommonJS. , ES-, , . , , ES-, , , , . ,
caniuse.com , 2018 ES- 80%.
ES-
Node.js.
▍ ES-
Node.js ES- .
import package from 'module-name'
CommonJS- .
const package = require('module-name')
, JavaScript-, - . 这是使用
export
关键字完成的。 , , , ,
uppercase.js
. .
export default str => str.toUpperCase()
, . .
( , ) .
HTML- ,
<script>
type="module"
.
<script type="module" src="index.js"></script>
,
(defer) . , ,
uppercase.js
, , , . -. , -. , VSCode, Live Server ( — ritwickdey.liveserver).
<!DOCTYPE html> <html> <head> </head> <body> <script type="module"> import toUpperCase from './uppercase.js' console.log(toUpperCase('hello')) </script> </body> </html>
HELLO
.
URL.
import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'
, ,
./
/
.
▍
, .
export default str => str.toUpperCase()
.
const a = 1 const b = 2 const c = 3 export { a, b, c }
module.js
, , , .
<html> <head> </head> <body> <script type="module"> import * as m from './module.js' console.log(ma, mb, mc) </script> </body> </html>
1 2 3
.
, , .
import { a } from './module.js' import { a, b } from './module.js'
, , .
console.log(a)
:
import { a, b as two } from './module.js'
, , , , .
module.js
.
const a = 1 const b = 2 const c = 3 export { a, b, c } export default () => console.log('hi')
.
import sayHi, { a } from './module.js' console.log(a) sayHi()
.
▍CORS
CORS . , CORS, (
Access-Control-Allow-Origin: *
).
▍ nomodule
, , ,
script ,
nomodule
. , , .
<script type="module" src="module.js"></script> <script nomodule src="fallback.js"></script>
▍ ES6 WebPack
ES6 — , , ECMAScript. , , , , . ,
WebPack, , , .
▍ CommonJS
, Node.js CommonJS. , . CommonJS npm.
CommonJS-, , . ,
up-node.js
.
exports.uppercase = str => str.toUpperCase()
, .
const up = require('./up-node.js') console.log(up.uppercase('hello'))
HELLO
.
, npm, , .
const package = require('module-name')
CommonJS , . .
CommonJS- .
exports.a = 1 exports.b = 2 exports.c = 3
, .
const { a, b, c } = require('./up-node.js')
, JavaScript — .
Math
, . , , JS- .
▍
(+)
+
. :
const three = 1 + 2
, , , .
'three' + 1
(-)
const two = 4 - 2
(/)
.
20 / 5
0, .
Infinity
( ) -
Infinity
( ).
1 / 0
(%)
%
, .
20 % 5
0
NaN
(Not a Number — ).
1 % 0
(*)
1 * 2
(**)
, .
1 ** 2
▍
(++)
++
1
. .
—
1
, .
let x = 0 ++x
— , .
let x = 0 x++
(--)
--
++
,
1
, .
let x = 0 x--
(-)
.
let x = 2 -x
(+)
, , . — .
let x = 2 +x
▍
JavaScript, (
=
), , . , ,
+=
.
let x = 2 x += 3 x
: « , , , , ». , .
let x = 2 x = x + 3 x
:
▍
. , .
const a = 1 * 2 + 5 / 2 % 2
2.5
. , . , .
- + ++ --
— ,/ %
— , ,+ -
—= += -= *= /= %= **=
—
, , . , .
const a = 1 * 2 + 5 / 2 % 2 const a = 2 + 2.5 % 2 const a = 2 + 0.5 const a = 2.5
. .
const a = 1 * (2 + 5) / 2 % 2
1.5
.
▍ Math
Math
, .
. , .
, ,
Math.E
— , e,
Math.PI
— , π.
Math.E
.
Math.abs()
—Math.ceil()
— , ,Math.cos()
— ,Math.floor()
— , ,Math.max()
—Math.min()
—Math.random()
— [0, 1) ( 1)Math.round()
—Math.sqrt()
—
▍
JavaScript , .
, . , , , .
.
<
— «»>
— «».<=
— « ».>=
— « ».
, .
1 === true
, ,
1
true
.
1
true
,
1
true
.
, , . Node.js. , :
PDF- Node.js.
总结
, this, , , . , ES6.
亲爱的读者们! , JavaScript?
