您现在的位置是:首页 > 正文

JS系列:分享 75 个精选的 JavaScript 基础知识点(上)

2024-02-01 02:22:43阅读 6

目录

1.undefined 和 null 有什么区别?

首先看一下他们的共同点

接着来看看它们的区别

2. && 运算符能做什么

3. || 运算符能做什么

4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?

5. DOM 是什么?

6. 什么是事件传播?

 7. 什么是事件冒泡?

8. 什么是事件捕获?

9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?

10. 如何知道是否在元素中使用了event.preventDefault()方法?

11. 为什么此代码 obj.someprop.x 会引发错误?

12. 什么是 event.target ?

13. 什么是 event.currentTarget??

14. == 和 === 有什么区别?

15. 为什么在 JS 中比较两个相似的对象时返回 false?

16. !! 运算符能做什么?

17. 如何在一行中计算多个表达式的值?

18. 什么是提升?(JS的预编译机制)

19. 什么是作用域?

20. 什么是闭包?

21. JavaScript 中的虚值是什么?

22. 如何检查值是否虚值?

23. 'use strict' 是干嘛用的?

 24. JavaScript 中 this 值是什么?

25. 对象的 prototype(原型) 是什么?


1.undefined 和 null 有什么区别?

在理解undefinednull之间的差异之前,我们先来看看它们的相似类。

首先看一下他们的共同点

它们属于 JavaScript 的 7 种基本类型

let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];

        它们是属于虚值,可以使用Boolean(value)!!value将其转换为布尔值时,值为false

JS中,一个!是将对象转为布尔型并取反,两个!是将取反后的布尔值再取反,相当于直接将非布尔类型值转为布尔类型值

console.log(!!null); // false
console.log(!!undefined); // false

console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false

接着来看看它们的区别

  undefined是未指定特定值的变量的默认值,或者没有显式返回值的函数(变量定义未赋值,默认值是undefined),如:console.log(1),还包括对象中不存在的属性,这些 JS 引擎都会为其分配 undefined 值。

let _thisIsUndefined;
const doNothing = () => {};
const someObj = {
  a : "ay",
  b : "bee",
  c : "si"
};
// 变量定义为赋值,是undefined
console.log(_thisIsUndefined); // undefined
// 箭头函数,中间上面也不写,是undefined
console.log(doNothing()); // undefined
// 对象中没有该属性,是undefined
console.log(someObj["d"]); // undefined

  null是“不代表任何值的值”。null是已明确定义给变量的值。(实际上null是一个“期望”对象。在此示例中,当fs.readFile方法未引发错误时,我们将获得null值。

fs.readFile('path/to/file', (e,data) => {
   console.log(e); // 当没有错误发生时,打印 null
   if(e){
     console.log(e);
   }
   console.log(data);
 });

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

 console.log(null == undefined); // true
 console.log(null === undefined); // false

2. && 运算符能做什么

  && 也可以叫逻辑与,在其操作数中找到第一个虚值表达式并返回它,如果没有找到任何虚值表达式(false),则返回最后一个真值表达式(true)。它采用短路来防止不必要的工作。

        && 就是在表达式中找到第一个false就返回他,如果没有找到,就返回最后一个值。

console.log(false && 1 && []); // false
console.log(" " && true && 5); // 5

3. || 运算符能做什么

  ||也叫或逻辑或,在其操作数中找到第一个真值表达式并返回它。这也使用了短路来防止不必要的工作。在支持 ES6 默认函数参数之前,它用于初始化函数中的默认参数值。

        || 就是在表达式中,找到第一个true,找到后返回他

console.log(null || 1 || undefined); // 1

function logName(name) {
  var n = name || "Mark";
  console.log(n);
}

logName(); // "Mark"

4. 使用 + 或一元加运算符是将字符串转换为数字的最快方法吗?

 是将字符串转换为数字的最快方法,因为如果值已经是数字,它不会执行任何操作。

5. DOM 是什么?

        DOM 代表文档对象模型,是 HTML 和 XML 文档的接口(API)。当浏览器第一次读取(解析)HTML文档时,它会创建一个大对象,一个基于 HTML文档的非常大的对象,这就是DOM。它是一个从 HTML 文档中建模的树状结构。DOM 用于交互和修改DOM结构或特定元素或节点。

假设我们有这样的 HTML 结构:

 <!DOCTYPE html>
  <html lang="en">

  <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <title>Document Object Model</title>
  </head>

  <body>
     <div>
        <p>
           <span></span>
        </p>
        <label></label>
        <input>
     </div>
  </body>

  </html>

 等价的DOM是这样的:

        JS 中的document对象表示DOM。它为我们提供了许多方法,我们可以使用这些方法来选择元素来更新元素内容,等等。

6. 什么是事件传播?

        当事件发生在DOM元素上时,该事件并不完全发生在那个元素上。在“冒泡阶段”中,事件冒泡或向上传播至父级,祖父母,祖父母或父级,直到到达window为止(由内到外);而在“捕获阶段”中,事件从window开始向下触发元素 事件或event.target(由外到内

事件传播有三个阶段

  1. 捕获阶段–事件从 window 开始,然后向下到每个元素,直到到达目标元素。

  2. 目标阶段–事件已达到目标元素。

  3. 冒泡阶段–事件从目标元素冒泡,然后上升到每个元素,直到到达 window

 7. 什么是事件冒泡?

        当事件发生在DOM元素上时,该事件并不完全发生在那个元素上。在冒泡阶段,事件冒泡,或者事件发生在它的父代,祖父母,祖父母的父代,直到到达window为止

假设有如下的 HTML 结构:

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

 对应的 JS 代码:

function addEvent(el, event, callback, isCapture = false) {
  if (!el || !event || !callback || typeof callback !== 'function') return;
  if (typeof el === 'string') {
    el = document.querySelector(el);
  };
  el.addEventListener(event, callback, isCapture);
}

addEvent(document, 'DOMContentLoaded', () => {
  const child = document.querySelector('.child');
  const parent = document.querySelector('.parent');
  const grandparent = document.querySelector('.grandparent');

  addEvent(child, 'click', function (e) {
    console.log('child');
  });

  addEvent(parent, 'click', function (e) {
    console.log('parent');
  });

  addEvent(grandparent, 'click', function (e) {
    console.log('grandparent');
  });

  addEvent(document, 'click', function (e) {
    console.log('document');
  });

  addEvent('html', 'click', function (e) {
    console.log('html');
  })

  addEvent(window, 'click', function (e) {
    console.log('window');
  })

});

  addEventListener方法具有第三个可选参数useCapture,其默认值为false,事件将在冒泡阶段中发生,如果为true,则事件将在捕获阶段中发生。如果单击child元素,它将分别在控制台上记录childparentgrandparenthtmldocumentwindow,这就是事件冒泡。

8. 什么是事件捕获?

        当事件发生在 DOM 元素上时,该事件并不完全发生在那个元素上。在捕获阶段,事件从window开始,一直到触发事件的元素

9. event.preventDefault() 和 event.stopPropagation()方法之间有什么区别?

  event.preventDefault() 方法可防止元素的默认行为。如果在表单元素中使用,它将阻止其提交。如果在锚元素中使用,它将阻止其导航。如果在上下文菜单中使用,它将阻止其显示或显示。event.stopPropagation()方法用于阻止捕获和冒泡阶段中当前事件的进一步传播

10. 如何知道是否在元素中使用了event.preventDefault()方法?

        我们可以在事件对象中使用event.defaultPrevented属性。它返回一个布尔值用来表明是否在特定元素中调用了event.preventDefault()

11. 为什么此代码 obj.someprop.x 会引发错误?

const obj = {};
console.log(obj.someprop.x);

        显然,由于我们尝试访问someprop属性中的x属性,而 someprop 并没有在对象中,所以值为 undefined记住:对象本身不存在的属性,并且其原型的默认值为undefined。因为undefined没有属性x,所以试图访问将会报错。(因为obj.someprop是undefined,但是undefined没用x属性,所以报错了

12. 什么是 event.target ?

        简单来说,event.target是发生事件的元素或触发事件的元素。

假设有如下的 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>

JS 代码如下:

function clickFunc(event) {
  console.log(event.target);
}

        如果单击 button,即使我们将事件附加在最外面的div上,它也将打印 button 标签,因此我们可以得出结论event.target触发事件的元素

13. 什么是 event.currentTarget??

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>

JS 代码如下:

function clickFunc(event) {
  console.log(event.currentTarget);
}

        如果单击 button,即使我们单击该 button,它也会打印最外面的div标签。在此示例中,我们可以得出结论,event.currentTarget是附加事件处理程序的元素(即:触发这个事件的所有相关元素

14. == 和 === 有什么区别?

  =用于一般比较,===用于严格比较,==在比较的时候可以转换数据类型,===严格比较,只要类型不匹配就返回flase

先来看看 == 这兄弟:

强制是将值转换为另一种类型的过程。在这种情况下,==会执行隐式强制。在比较两个值之前,==需要执行一些规则。

假设我们要比较x == y的值。

  1. 如果xy的类型相同,则 JS 会换成===操作符进行比较。

  2. 如果xnullyundefined,则返回true

  3. 如果xundefinedynull,则返回true

  4. 如果x的类型是numbery的类型是string,那么返回x == toNumber(y)

  5. 如果x的类型是stringy的类型是number,那么返回toNumber(x) == y

  6. 如果x为类型是boolean,则返回toNumber(x)== y

  7. 如果y为类型是boolean,则返回x == toNumber(y)

  8. 如果xstringsymbolnumber,而yobject类型,则返回x == toPrimitive(y)

  9. 如果xobjectystringsymbol 则返回toPrimitive(x) == y

  10. 剩下的 返回 false

注意:toPrimitive首先在对象中使用valueOf方法,然后使用toString方法来获取该对象的原始值。

举个例子。

x y x == y
5 5 true
1 '1' true
null undefined true
0 false true
'1,2' [1,2] true
'[object Object]' {} true

这些例子都返回true

第一个示例符合条件1,因为xy具有相同的类型和值。

第二个示例符合条件4,在比较之前将y转换为数字。

第三个例子符合条件2

第四个例子符合条件7,因为yboolean类型。

第五个示例符合条件8。使用toString()方法将数组转换为字符串,该方法返回1,2

最后一个示例符合条件8。使用toString()方法将对象转换为字符串,该方法返回[object Object]

x y x === y
5 5 true
1 '1' false
null undefined false
0 false false
'1,2' [1,2] false
'[object Object]' {} false

        如果使用===运算符,则第一个示例以外的所有比较将返回false,因为它们的类型不同,而第一个示例将返回true,因为两者的类型和值相同。

15. 为什么在 JS 中比较两个相似的对象时返回 false?

先看下面的例子:

let a = { a: 1 };
let b = { a: 1 };
let c = a;

console.log(a === b); // 打印 false,即使它们有相同的属性
console.log(a === c); // true

        JS 以不同的方式比较对象和基本类型。基本类型中,JS 通过值对它们进行比较,而在对象中,JS 通过引用或存储变量的内存中的地址对它们进行比较。这就是为什么第一个console.log语句返回false,而第二个console.log语句返回trueac有相同的引用地址,而ab没有。

        简单来说:a和b都是对象类型,属于引用类型,所以在比较的时候,比较的是两个变量的地址,而这两个地址都是唯一的,所以a===b是false;当执行了c=a之后,进行了浅拷贝,变量c拷贝了变量a的地址,这时候,两个变量在执行a===c时,比较的a的地址,所以时true。

16. !! 运算符能做什么?

  !!运算符可以将右侧的值强制转换为布尔值,这也是将值转换为布尔值的一种简单方法。

console.log(!!null); // false
console.log(!!undefined); // false
console.log(!!''); // false
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!' '); // true
console.log(!!{}); // true
console.log(!![]); // true
console.log(!!1); // true
console.log(!![].length); // false

拓展:Boolean值为false的五个特殊的值:0null' 'undefinedfalse

17. 如何在一行中计算多个表达式的值?

        可以使用逗号运算符在一行中计算多个表达式。它从左到右求值,并返回右边最后一个项目或最后一个操作数的值。

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

18. 什么是提升?(JS的预编译机制)

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

函数的提升比var的提升优先级更高!!!

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

编译-在此阶段,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,1Hello 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"));

19. 什么是作用域?

        JavaScript 中的作用域是我们可以有效访问变量或函数的区域。JS 有三种类型的作用域:全局作用域函数作用域块作用域(ES6)

全局作用域——在全局命名空间中声明的变量或函数位于全局作用域中,因此在代码中的任何地方都可以访问它们。

//global namespace
var g = "global";

function globalFunc(){
  function innerFunc(){
    console.log(g); //能够找到“g”,因为g是一个全局变量
  }
 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(); //报错:"z" is define

       作用域也是一组用于查找变量的规则。如果变量在当前作用域中不存在,它将向外部作用域中查找并搜索,如果该变量不存在,它将再次查找直到到达全局作用域,如果找到,则可以使用它,否则引发错误,这种查找过程也称为作用域链

   /* 作用域链
     
     内部作用域->外部作用域-> 全局作用域
  */

  // 全局作用域
  var variable1 = "Comrades";   
  var variable2 = "Sayonara";

  function outer(){
  // 外部作用域
    var variable1 = "World";
    function inner(){
    // 内部作用域
      var variable2 = "Hello";
      console.log(variable2 + " " + variable1);
    }
    inner();
  }  
  outer(); // Hello World

20. 什么是闭包?

        这可能是所有问题中最难的一个问题,因为闭包是一个有争议的话题,这里从个人角度来谈谈,如果不妥,多多海涵。

        定义:闭包就是一个函数引用另一个函数内部的变量,因为变量被引用着,所以当另外一个函数执行结束,其相应的执行上下文弹出栈时, 变量并不会被回收,因此可以用来封装一个私有变量。不正当地使用闭包可能会造成内存泄漏。        面试题:说一下JS中的闭包和this的指向_小张快跑。的博客-CSDN博客说一下JS中的闭包和this的指向https://blog.csdn.net/io_123io_123/article/details/123665483?spm=1001.2014.3001.5501

21. JavaScript 中的虚值是什么?

 const falsyValues = ['', 0, null, undefined, NaN, false];

        简单的来说虚值就是是在转换为布尔值时变为 false 的值。

22. 如何检查值是否虚值?

        使用 Boolean 函数或者 !! 运算符

23. 'use strict' 是干嘛用的?

  "use strict" 是 ES5 特性,它使我们的代码在函数或整个脚本中处于严格模式严格模式帮助我们在代码的早期避免 bug,并为其添加限制。

严格模式的一些限制:

  1. 变量必须声明后再使用

  2. 函数的参数不能有同名属性,否则报错

  3. 不能使用with语句

  4. 不能对只读属性赋值,否则报错

  5. 不能使用前缀 0 表示八进制数,否则报错

  6. 不能删除不可删除的属性,否则报错

  7. 不能删除变量delete prop,会报错,只能删除属性delete global[prop]

  8. eval不能在它的外层作用域引入变量

  9. evalarguments不能被重新赋值

  10. arguments不会自动反映函数参数的变化

  11. 不能使用arguments.callee

  12. 不能使用arguments.caller

  13. 禁止this指向全局对象

  14. 不能使用fn.callerfn.arguments获取函数调用的堆栈

  15. 增加了保留字(比如protectedstaticinterface

设立”严格模式”的目的,主要有以下几个:

  1. 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;

  2. 消除代码运行的一些不安全之处,保证代码运行的安全;

  3. 提高编译器效率,增加运行速度;

  4. 为未来新版本的Javascript做好铺垫。

 24. JavaScript 中 this 值是什么?

        关于JS中this的指向问题以及改变this指向的方法,我在往期的文章中有更加详细的介绍:

分析几个面试题_小张快跑。的博客-CSDN博客面试题:箭头函数和普通函数的区别?call()和 apply()的区别和作用?keep-alive的作用是什么?sessionStorage和localeStorage的区别?JS中的深拷贝与浅拷贝的区别?https://blog.csdn.net/io_123io_123/article/details/123245831

25. 对象的 prototype(原型) 是什么?

        简单地说,原型就是对象的蓝图。如果它存在当前对象中,则将其用作属性和方法的回退。它是在对象之间共享属性和功能的方法,这也是JavaScript实现继承的核心。        

const o = {};
console.log(o.toString()); // logs [object Object] 

        即使o对象中不存在o.toString方法,它也不会引发错误,而是返回字符串[object Object]当对象中不存在属性时,它将查看其原型,如果仍然不存在,则将其查找到原型的原型,依此类推,直到在原型链中找到具有相同属性的属性为止。原型链的末尾是Object.prototype

console.log(o.toString === Object.prototype.toString); // logs true

有关JS部分的面试题系列,还在持续更新中。。。

网站文章

  • [LeetCode 874] Maximum Vacation Days

    LintCode wants to give one of its best employees the option to travel amongNcities to collect algori...

    2024-02-01 02:22:14
  • 整数因子分解问题

    Problem Description 大于1 的正整数n可以分解为:n=x1*x2*…*xm。 例如,当n=12 时,共有8 种不同的分式: 12=12; 12=6*2; 12=4*3; 12=3*4; 12=3*2*2; 12=2*6; 12=2*3*2; 12=2*2*3。 编程任务: 对于给定的正整数n,编程计算n共有多少种不同的分解式。 Input

    2024-02-01 02:22:08
  • 操作系统国产化现状

    操作系统国产化现状

    在开源操作系统生态不断成熟的背景下,中国的国产操作系统依托开源生态和政策东风正快速崛起,市场潜力巨大,未来发展前景值得期待。中国桌面操作系统当前呈现两大特征:一是Windows+Inte...

    2024-02-01 02:22:01
  • java两个list的数据快速对比 map的使用

    1.思路: 把2个list数据放到map里面,利用map的containsKey进行快速比对 2. //数据1 List list1 = new ArrayList(); //数据2 List list2 = new ArrayList(); Map m...

    2024-02-01 02:21:32
  • PAT乙级-B1032 挖掘机技术哪家强(20)

    为了用事实说明挖掘机技术到底哪家强,PAT 组织了一场挖掘机技能大赛。现请你根据比赛结果统计出技术最强的那个学校。

    2024-02-01 02:21:26
  • Android中的内存管理

    当进程内存不够的时候,安卓会再分配一些内存给各个进程。回收的时候就可能杀死那些正在占用内存的进程。所以操作系统需要有一个合理的杀死占用内存的进程的机制,以保证把副作用降到最低。安卓系统会为每个进程合理...

    2024-02-01 02:21:19
  • Linux驱动中断和定时器

    Linux驱动中断和定时器

    Linux驱动中断和定时器一文搞定中断顶半部,底半部机制,硬件中断,软中断,Tasklet,工作队列,jiffies,定时器

    2024-02-01 02:20:50
  • 【学习笔记】初识websocket及其握手过程

    【学习笔记】初识websocket及其握手过程

    客户端收到应答后,要校验Sec-WebSocket-Key的值,如果该值和计算结果不符,或者不符合上面过程任一要求,则拒绝创建websocket连接。如果客户端校验无误,websocket就握手完成了。

    2024-02-01 02:20:44
  • 栈和队列的区别

    栈和队列的区别 1.规则不同 队列:先进先出 栈:先进后出 2.对插入和删除的限定不同 队列:只能在表的一段进行插入,并在另一端进行删除 栈:只能在表的一端插入和删除 3.遍历数据速度不同 队列:基于...

    2024-02-01 02:20:35
  • java lesson13Homework

    /** * 1. 字符串解析,现有字符串,“卡巴斯基#杀毒软件#免费版#俄罗斯#”,解析出每个元素。 */ package String13Practice; public class String01 { public static void main(String[] args){ String str=&quot;卡巴斯基#杀毒软件#免费版#俄罗斯#&quot;...

    2024-02-01 02:20:28