- JavaScript的内置类型
- undefined 和 null 有什么区别?
- 什么是闭包?
- 什么是作用域和作用域链?
- 如何理解this关键字
- 什么是事件传播?
- 什么是事件冒泡?
- 什么是事件捕获?
- event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?
- 如何知道是否在元素中使用了 event.preventDefault()方法?
- 什么是 event.target 和 event.currentTarget?
- == 和 === 有什么区别?
- 如何在一行中计算多个表达式的值?
- 什么是提升?
- JavaScript 中的虚值是什么?
- 'use strict' 是干嘛用的?
- load和DOMContentLoaded的区别
- input中如何监听值的变化
- 重绘Repaint和回流Reflow
- 什么是词法作用域和动态作用域
- JavaScript 的可执行代码(executable code)的类型有哪些
JavaScript的内置类型
6种原始类型: Boolean
, String
, Null
, undefined
, Number
, Symbol
引用类型: Object
, Function
undefined 和 null 有什么区别?
它们属于 JavaScript 的 7 种基本类型
- string
- number
- null
- undefined
- boolean
- symbol
- bigint
undefined
是未指定特定值的变量的默认值,或者没有显式返回值的函数,如:console.log(1)
,还包括对象中不存在的属性,这些 JS 引擎都会为其分配 undefined
值
let _thisIsUndefined;
const doNothing = () => {};
const someObj = {
a: "ay",
b: "bee",
c: "si"
};
console.log(_thisIsUndefined); // undefined
console.log(doNothing()); // undefined
console.log(someObj["d"]); // undefined
null
是“不代表任何值的值”。null
是已明确定义给变量的值
fs.readFile("path/to/file", (e, data) => {
console.log(e); // 当没有错误发生时,打印 null
if (e) {
console.log(e);
}
console.log(data);
});
在比较null
和undefined
时,我们使用==
时得到true
,使用===
时得到false
什么是闭包?
闭包
就是一个函数在声明时能够记住当前作用域、父函数作用域、及父函数作用域上的变量和参数的引用,直至通过作用域链上全局作用域,基本上闭包是在声明函数时创建的作用域。
使用闭包主要是为了设计私有的方法和变量。
闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
闭包有三个特性:
- 函数嵌套函数
- 函数内部可以引用外部的参数和变量
- 参数和变量不会被垃圾回收机制回收
什么是作用域和作用域链?
JavaScript
中的作用域基本上是变量以及如何通过名称访问这些变量的规则的集合
JS
有三种类型的作用域:全局作用域、函数作用域和块作用域(ES6)。
全局作用域
——在全局命名空间中声明的变量或函数位于全局作用域中,因此在代码中的任何地方都可以访问它们
一个作用域可以嵌套在另一个作用域内。如果一个作用域嵌套在另一个作用域内,最内部作用域内的代码可以访问另一个作用域的变量
//global namespace
var g = "global";
function globalFunc() {
function innerFunc() {
console.log(g); // can access "g" because "g" is a global variable
}
innerFunc();
}
函数作用域
——在函数中声明的变量、函数和参数可以在函数内部访问,但不能在函数外部访问。
function myFavoriteFunc(a) {
if (true) {
var b = "Hello " + a;
}
return b;
}
myFavoriteFunc("World");
console.log(a); // Throws a ReferenceError "a" is not defined
console.log(b); // does not continue here
块作用域
-在块{}
中声明的变量(let
,const
)只能在其中访问
function testBlock() {
if (true) {
let z = 5;
}
return z;
}
testBlock(); // Throws a ReferenceError "z" is not defined
作用域也是一组用于查找变量的规则。如果变量在当前作用域中不存在,它将向外部作用域中查找并搜索,如果该变量不存在,它将再次查找直到到达全局作用域,如果找到,则可以使用它,否则引发错误,这种查找过程也称为作用域链
。
/* 作用域链
内部作用域->外部作用域-> 全局作用域
*/
// 全局作用域
var variable1 = "Comrades";
var variable2 = "Sayonara";
function outer(){
// 外部作用域
var variable1 = "World";
function inner(){
// 内部作用域
var variable2 = "Hello";
console.log(variable2 + " " + variable1);
}
inner();
}
outer(); // Hello World
如何理解this关键字
this
表示当前对象,this
的指向是根据调用的上下文来决定的,默认指向window
对象
全局环境:全局环境就是在里面,这里的this始终指向的是window
对象
局部环境:
- 在全局作用域下直接调用函数,
this
指向window
- 对象函数调用,哪个对象调用就指向哪个对象
- 使用
new
实例化对象,在构造函数中的this
指向实例化对象 - 使用
call
或apply
改变this
的指向
掌握 JavaScript 中的 this,call,apply 的原理
什么是事件传播?
当事件发生在DOM
元素上时,该事件并不完全发生在那个元素上。在“冒泡阶段”中,事件冒泡或向上传播至父级,祖父母,祖父母或父级,直到到达window
为止;而在“捕获阶段”中,事件从window
开始向下触发元素 事件或event.target
。
事件传播有三个阶段:
-
捕获阶段–事件从
window
开始,然后向下到每个元素,直到到达目标元素。 -
目标阶段–事件已达到目标元素。
-
冒泡阶段–事件从目标元素冒泡,然后上升到每个元素,直到到达
window
什么是事件冒泡?
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
如果单击child
元素,它将分别在控制台上记录child
,parent
,grandparent
,html
,document
和window
,这就是事件冒泡。
什么是事件捕获?
<div class="grandparent">
<div class="parent">
<div class="child">1</div>
</div>
</div>
如果单击child
元素,它将分别在控制台上记录window
,document
,html
,grandparent
,parent
和child
,这就是事件冒泡。
event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?
event.preventDefault()
方法可防止元素的默认行为
- 如果在表单元素中使用,它将阻止其提交
- 如果在锚元素中使用,它将阻止其导航
- 如果在上下文菜单中使用,它将阻止其显示或显示
event.stopPropagation()
方法用于阻止捕获和冒泡阶段中当前事件的进一步传播
如何知道是否在元素中使用了 event.preventDefault()方法?
我们可以在事件对象中使用event.defaultPrevented
属性。它返回一个布尔值用来表明是否在特定元素中调用了event.preventDefault()
什么是 event.target 和 event.currentTarget?
简单来说,event.target
是发生事件的元素或触发事件的元素, event.currentTarget
是我们在其上显式附加事件处理程序的元素
假设有如下的 HTML 结构:
<div
onclick="clickFunc(event)"
style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;"
>
<div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
<div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
<button style="margin:10px">Button</button>
</div>
</div>
</div>
如果单击 button
,即使我们将事件附加在最外面的div
上,它也将打印 button
标签,因此我们可以得出结论event.target
是触发事件的元素。
如果单击 button
,即使我们单击该 button
,它也会打印最外面的div
标签。在此示例中,我们可以得出结论,event.currentTarget
是附加事件处理程序的元素
== 和 === 有什么区别?
JavaScript 中有严格比较和类型转换比较:
严格比较(例如 ===)在不允许强制转型的情况下检查两个值是否相等
类型转换比较(例如 ==)在允许强制转型的情况下检查两个值是否相等
==
用于一般比较,===
用于严格比较,==
在比较的时候可以转换数据类型,===
严格比较,只要类型不匹配就返回flase
如何在一行中计算多个表达式的值?
可以使用逗号运算符在一行中计算多个表达式。它从左到右求值,并返回右边最后一个项目或最后一个操作数的值。
let x = 5;
x = (x++, (x = addFive(x)), (x *= 2), (x -= 5), (x += 10));
function addFive(num) {
return num + 5;
}
上面的结果最后得到 x 的值为27
。首先,我们将x
的值增加到6
,然后调用函数addFive(6)
并将6
作为参数传递并将结果重新分配给x
,此时x
的值为11
。之后,将x
的当前值乘以 2
并将其分配给x
,x
的更新值为22
。然后,将x
的当前值减去 5
并将结果分配给x
x
更新后的值为17
。最后,我们将x
的值增加10
,然后将更新的值分配给x
,最终x
的值为27
什么是提升?
提升
是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语。
为了理解提升,需要来了解一下执行上下文。执行上下文
是当前正在执行的“代码环境”。执行上下文
有两个阶段:编译
和执行
。
编译
-在此阶段,JS
引荐获取所有函数声明并将其提升到其作用域的顶部,以便我们稍后可以引用它们并获取所有变量声明(使用 var 关键字进行声明),还会为它们提供默认值:undefined
。
执行
——在这个阶段中,它将值赋给之前提升的变量,并执行或调用函数(对象中的方法)。
注意:只有使用var
声明的变量,或者函数声明
才会被提升,相反,函数表达式
或箭头函数
,let
和const
声明的变量,这些都不会被提升。
假设在全局使用域,有如下的代码:
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
function greet(name) {
return "Hello " + name + "!";
}
var y;
上面分别打印:undefined
,1
, Hello Mark!
。
上面代码在编译阶段其实是这样的:
function greet(name) {
return "Hello " + name + "!";
}
var y; // 默认值 undefined
// 等待“编译”阶段完成,然后开始“执行”阶段
/*
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
*/
编译阶段完成后,它将启动执行阶段调用方法,并将值分配给变量。
function greet(name) {
return "Hello " + name + "!";
}
var y;
//start "execution" phase
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
JavaScript 中的虚值是什么?
const falsyValues = ["", 0, null, undefined, NaN, false];
简单的来说虚值就是是在转换为布尔值时变为 false
的值。
'use strict' 是干嘛用的?
"use strict"
是 ES5 特性,它使我们的代码在函数或整个脚本中处于严格模式。严格模式帮助我们在代码的早期避免 bug,并为其添加限制
设立”严格模式”的目的,主要有以下几个:
-
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
-
消除代码运行的一些不安全之处,保证代码运行的安全;
-
提高编译器效率,增加运行速度;
-
为未来新版本的Javascript做好铺垫。
load和DOMContentLoaded的区别
load:
load
应该仅用于检测一个完全加载的页面 当一个资源及其依赖资源已完成加载时,将触发load
事件.即页面的HTML
, CSS
, JavaScript
图片等资源都已经加载完之后才会触发 load
事件
DOMContentLoaded:
当初始的 HTML
文档被完全加载和解析完成之后,DOMContentLoaded
事件被触发,而无需等待样式表、图像和子框架的完成加载. 即HTML
下载、解析完毕之后就触发
input中如何监听值的变化
可以实时监听值的变化的事件有以下几种
- keypress
- keydown
- keyup
- input
注: onChange
无法做到实时监听,因为 onChange
需要失去焦点才能触发
重绘Repaint和回流Reflow
重绘Repaint和回流(重排)Reflow【笔记 && 非原创】
什么是词法作用域和动态作用域
词法作用域: 函数的作用域在函数定义时决定 动态作用域: 函数的作用域在函数调用时决定
JavaScript 的可执行代码(executable code)的类型有哪些
全局代码、函数代码、eval代码
举个例子,当执行到一个函数的时候,就会进行准备工作,这里的“准备工作”,让我们用个更专业一点的说法,就叫做"执行上下文(execution context)"