JavaScript知识点总结[个人笔记]

148 阅读11分钟

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

在比较nullundefined时,我们使用==时得到true,使用===时得到false

什么是闭包?

闭包就是一个函数在声明时能够记住当前作用域、父函数作用域、及父函数作用域上的变量和参数的引用,直至通过作用域链上全局作用域,基本上闭包是在声明函数时创建的作用域。

使用闭包主要是为了设计私有的方法和变量。

闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

闭包有三个特性:

  1. 函数嵌套函数
  2. 函数内部可以引用外部的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

什么是作用域和作用域链?

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

块作用域-在块{}中声明的变量(letconst)只能在其中访问

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对象

局部环境:

  1. 在全局作用域下直接调用函数,this指向window
  2. 对象函数调用,哪个对象调用就指向哪个对象
  3. 使用 new 实例化对象,在构造函数中的this指向实例化对象
  4. 使用callapply改变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元素,它将分别在控制台上记录childparentgrandparenthtmldocumentwindow,这就是事件冒泡。

什么是事件捕获?

<div class="grandparent">
  <div class="parent">
    <div class="child">1</div>
  </div>
</div>

如果单击child元素,它将分别在控制台上记录windowdocumenthtmlgrandparentparentchild,这就是事件冒泡。

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 并将其分配给xx的更新值为22。然后,将x的当前值减去 5 并将结果分配给x x更新后的值为17。最后,我们将x的值增加10,然后将更新的值分配给x,最终x的值为27

什么是提升?

提升是用来描述变量和函数移动到其(全局或函数)作用域顶部的术语。

为了理解提升,需要来了解一下执行上下文。执行上下文是当前正在执行的“代码环境”。执行上下文有两个阶段:编译执行

编译-在此阶段,JS 引荐获取所有函数声明并将其提升到其作用域的顶部,以便我们稍后可以引用它们并获取所有变量声明(使用 var 关键字进行声明),还会为它们提供默认值:undefined

执行——在这个阶段中,它将值赋给之前提升的变量,并执行或调用函数(对象中的方法)。

注意:只有使用var声明的变量,或者函数声明才会被提升,相反,函数表达式箭头函数letconst声明的变量,这些都不会被提升。

假设在全局使用域,有如下的代码:

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)"