pingan8787 / Leo-JavaScript

欢迎关注公众号“前端自习课”,本仓库包含丰富的前端学习资料,包括 JavaScript、前端框架、HTTP、GraphQL、TS、Vue、React、Webpack等,还有很多我的原创文章,喜欢的朋友欢迎stat。:rocket:持续更新中...
https://www.yuque.com/wangpingan
987 stars 164 forks source link

【基础】初中级前端 JavaScript 自测清单 - 1 #50

Open pingan8787 opened 2 years ago

pingan8787 commented 2 years ago

最近原创文章🔥:


前言

最近与部门老大一起面试了许多前端求职者,其中想换个学习氛围较好的人占多数,但良好的学习氛围也是需要一点点营造出来的🌺。

为此我们组建了我们团队内部的“现代 JavaScript 突击队”,第一期学习内容为《现代 JavaScript 教程》系列,帮助小组成员系统地进行学习巩固,并让大家养成系统性学习和输出学习总结的学习方式

本文作为我输出的第一部分学习总结,希望作为一份自测清单,帮助大家巩固知识,温故知新。

这里也下面分享我们学习小组的“押金制度”和“押金记录表”🍀

“押金制度”和“押金记录表”

接下来开始分享自测清单的内容。

初中级前端 JavaScript 自测清单.png

一、Hello World!

1. 脚本引入方式

JavaScript 脚本引入方式有两种:

2. script 标签属性

<script>  标签有以下常用属性:

2.1 src

src :指定外部脚本的URI, 如果设置了 src 特性,script 标签内容将会被忽略;

<script src="example-url.js"></script>

2.2 type

type :指定引用脚本的语言,属性值为 MIME 类型,包括text/javascript, text/ecmascript, application/javascript, 和application/ecmascript。如果没有定义这个属性,脚本会被视作JavaScript。

ES6 新增了属性值 module ,代码会被当做 JavaScript 模块。

<script type="text/javascript"></script>

2.3 async

async 规定一旦脚本可用,则会异步执行。 注意:async 属性仅适用于外部脚本(只有在使用 src 属性时)。 有多种执行外部脚本的方法: 如果 async="async" :脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行); 如果不使用 async  且 defer="defer" :脚本将在页面完成解析时执行; 如果既不使用 async 也不使用 defer :在浏览器继续解析页面之前,立即读取并执行脚本;

<script async="async"></script>

2.4 defer

defer 属性规定是否对脚本执行进行延迟,直到页面加载为止。

如果您的脚本不会改变文档的内容,可将 defer 属性加入到 <script> 标签中,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。

<script defer="defer"></script>

详细介绍可以阅读《MDN <script>章节 》

二、代码结构

1. 语句

语句是执行行为(action)的语法结构和命令。如: alert('Hello, world!') 这样可以用来显示消息的语句。

2. 分号

存在分行符时,多数情况下可以省略分号。但不全是,比如:

alert(3 +
1
+ 2);

建议新人最好不要省略分号。

3. 注释

单行注释以两个正斜杠字符 // 开始。

// 注释文本
console.log("leo");

多行注释以一个正斜杠和星号开始 “/*” 并以一个星号和正斜杆结束 “*/”

/*
这是多行注释。
第二行注释。
*/
console.log("leo");

三、现代模式,"use strict"

1. 作用

JavaScript 的严格模式是使用受限制的 JavaScript 的一种方式,从而隐式地退出“草率模式”。

"use strict" 指令将浏览器引擎转换为“现代”模式,改变一些内建特性的行为。

2. 使用

通过在脚本文件/函数开头添加 "use strict"; 声明,即可启用严格模式。 全局开启严格模式:

// index.js
"use strict";
const v = "Hi!  I'm a strict mode script!";

函数内开启严格模式:

// index.js
function strict() {
  'use strict';
  function nested() { 
    return "And so am I!"; 
  }
  return "Hi!  I'm a strict mode function!  " + nested();
}

3. 注意点

  1. "use strict" 需要定义在脚本最顶部(函数内除外),否则严格模式可能无法启用。
  2. 一旦进入了严格模式,就无法关闭严格模式。

4. 体验

启用 "use strict" 后,为未定义元素赋值将抛出异常:

"use strict";
leo = 17; // Uncaught ReferenceError: leo is not defined

启用 "use strict" 后,试图删除不可删除的属性时会抛出异常:

"use strict";
delete Object.prototype; // Uncaught TypeError: Cannot delete property 'prototype' of function Object() { [native code] }

详细介绍可以阅读《MDN 严格模式章节 》

四、变量

1. 介绍

变量是数据的“命名存储”。

2. 使用

目前定义变量可以使用三种关键字:var / let / const。三者区别可以阅读《let 和 const 命令》

let name = "leo";
let name = "leo", age, addr;
let name = "leo", age = 27, addr = "fujian";

3. 命名建议

变量命名有 2 个限制:

  1. 变量名称必须仅包含字母,数字,符号 $_
  2. 首字符必须非数字。 变量命名还有一些建议:
    • 常量一般用全大写,如 const PI = 3.141592
    • 使用易读的命名,比如 userName 或者 shoppingCart

4. 注意点

五、数据类型

JavaScript 是一种弱类型或者说动态语言。这意味着你不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。这也意味着你可以使用同一个变量保存不同类型的数据:

var foo = 42;    // foo is a Number now
foo = "bar"; // foo is a String now
foo = true;  // foo is a Boolean now

详细介绍可以阅读《MDN JavaScript 数据类型和数据结构 》

1. 八大数据类型

前七种为基本数据类型,也称为原始类型(值本身无法被改变),而 object 为复杂数据类型。 八大数据类型分别是:

2. 检测数据类型

通过 typeof 运算符检查:

2. 数值转换

通过以下几种方式能将其他类型数据转换为 Number 类型:

2、+ 号运算符

let msg = "hello " + "leo"; // "hello leo"
let total = 10 + 20;  // 30
let text1 = "1" + "2"; // "12"
let text2 = "1" + 2;   // "12"
let text3 = 1 + "2";   // "12"
let text4 = 1 + 2 + "3";  // "33"
let num = +text1; //  12 转换为 Number 类型

3、运算符优先级

运算符的优先级决定了表达式中运算执行的先后顺序,优先级高的运算符最先被执行。 下面的表将所有运算符按照优先级的不同从高(20)到低(1)排列。 优先级 运算类型 关联性 运算符
20 圆括号 n/a(不相关) ( … )
19 成员访问 从左到右 … . …
需计算的成员访问 从左到右 … [ … ]
new (带参数列表) n/a new … ( … )
函数调用 从左到右 … ( … )
可选链(Optional chaining) 从左到右 ?.
18 new (无参数列表) 从右到左 new …
17 后置递增(运算符在后) n/a
… ++
后置递减(运算符在后) … --
16 逻辑非 从右到左 ! …
按位非 ~ …
一元加法 + …
一元减法 - …
前置递增 ++ …
前置递减 -- …
typeof typeof …
void void …
delete delete …
await await …
15 从右到左 … ** …
14 乘法 从左到右
… * …
除法 … / …
取模 … % …
13 加法 从左到右
… + …
减法 … - …
12 按位左移 从左到右 … << …
按位右移 … >> …
无符号右移 … >>> …
11 小于 从左到右 … < …
小于等于 … <= …
大于 … > …
大于等于 … >= …
in … in …
instanceof … instanceof …
10 等号 从左到右
… == …
非等号 … != …
全等号 … === …
非全等号 … !== …
9 按位与 从左到右 … & …
8 按位异或 从左到右 … ^ …
7 按位或 从左到右 … | …
6 逻辑与 从左到右 … && …
5 逻辑或 从左到右 … || …
4 条件运算符 从右到左 … ? … : …
3 赋值 从右到左 … = …
… += …
… -= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
2 yield 从右到左 yield …
yield* yield* …
1 展开运算符 n/a ...
0 逗号 从左到右 … , …
3 > 2 && 2 > 1
// return true
3 > 2 > 1
// 返回 false,因为 3 > 2 是 true,并且 true > 1 is false
// 加括号可以更清楚:(3 > 2) > 1

八、值的比较

1. 常见比较

在 JS 中的值的比较与数学很类型:

3. confirm

Window.confirm() 方法显示一个具有一个可选消息和两个按钮(确定和取消)的模态对话框。 注意:弹出模态框,并暂停脚本,直到用户点击“确定”按钮。 语法如下:

let result = window.confirm(message);

十、条件运算符:if 和 '?'

1. if 语句

当 if 语句当条件表达式,会将表达式转换为布尔值,当为 truthy 时执行里面代码。 转换规则如:

十一、逻辑运算符

详细可以阅读《MDN 逻辑运算符》

1. 运算符介绍

逻辑运算符如下表所示 (其中_expr_可能是任何一种类型, 不一定是布尔值): 运算符 语法 说明
逻辑与,AND(&& _expr1_ && _expr2_ expr**1** 可转换为 true,则返回 expr**2**;否则,返回 expr**1**
逻辑或,OR(|| _expr1_ || _expr2_ expr**1** 可转换为 true,则返回 expr**1**;否则,返回 expr**2**
逻辑非,NOT(! !_expr_ expr 可转换为 true,则返回 false;否则,返回 true

如果一个值可以被转换为 true,那么这个值就是所谓的 truthy,如果可以被转换为 false,那么这个值就是所谓的 falsy。 会被转换为 false 的表达式有:

2. 运算符示例

3. 布尔值转换规则

4. 短路取值

由于逻辑表达式的运算顺序是从左到右,也可以用以下规则进行"短路"计算:

十二、循环:while 和 for

1. while 循环

详细可以阅读《MDN  while》while 语句可以在某个条件表达式为真的前提下,循环执行指定的一段代码,直到那个表达式不为真时结束循环。 如:

var n = 0;
var x = 0;
while (n < 3) {
  n++;
  x += n;
}

当循环体为单行时,可以不写大括号:

let i = 3;
while(i) console.log(i --);

2. do...while 循环

详细可以阅读《MDN  do...while》do...while 语句创建一个执行指定语句的循环,直到condition值为 false。在执行statement 后检测condition,所以指定的statement至少执行一次。 如:

var result = '';
var i = 0;
do {
   i += 1;
   result += i + ' ';
} while (i < 5);

3. for 循环

详细可以阅读《MDN  for》for 语句用于创建一个循环,它包含了三个可选的表达式,这三个表达式被包围在圆括号之中,使用分号分隔,后跟一个用于在循环中执行的语句(通常是一个块语句)。 语法如:

for (begin; condition; step) {
  // ……循环体……
}

示例:

for (let i = 0; i < 3; i++) {
  console.log(i);
}
描述: begin i = 0 进入循环时执行一次。
condition i < 3 在每次循环迭代之前检查,如果为 false,停止循环。
body(循环体) alert(i) 条件为真时,重复运行。
step i++ 在每次循环体迭代后执行。

4. 可选的 for 表达式

for 语句头部圆括号中的所有三个表达式都是可选的。

十三、"switch" 语句

switch 语句用来将表达式的值与 case 语句匹配,并执行与情况对应的语句。 switch 语句可以替代多个 if 判断,为多个分支选择的情况提供一个更具描述性的方式。

1. 语法

switch 语句至少包含一个 case 代码块和一个可选的 default 代码块:

switch(expression) {
  case 'value1':
    // do something ...
    [break]

  default:
    // ...
    [break]
}

expression 表达式的值与 value1 匹配时,则执行其中代码块。 如果没有 case  子句匹配,则会选择 default 子句执行,若连 default 子句都没有,则直接执行到 switch 结束。

2. 使用 case 分组

所谓 case 分组,就是与多个 case 分支共享同一段代码,如下面例子中 case 1  和 case 2

let a = 2;
switch (a) {
  case 1: // (*) 下面这两个 case 被分在一组
  case 2:
    console.log('case is 1 or 2!');
    break;
  case 3:
    console.log('case is 3!');
    break;
  default:
    console.log('The result is default.');
}
// 'case is 1 or 2!'

3. 注意点

  1. expression 表达式的值与 case 值的比较是严格相等:
    function f(n){
    let a ;
    switch(n){
        case 1:
            a = 'number';
            break;
        case '1':
            a = 'string';
            break;
        default:
            a = 'default';
            break;
    }
    console.log(a)
    }
    f(1);   // number
    f('1'); // string
  2. 如果没有 break,程序将不经过任何检查就会继续执行下一个 **case** :
    let a = 2 + 2;
    switch (a) {
    case 3:
    console.log( 'Too small' );
    case 4:
    console.log( 'Exactly!' );
    case 5:
    console.log( 'Too big' );
    default:
    console.log( "I don't know such values" );
    }
    // Exactly!
    // Too big
    // I don't know such values
  3. **default** 放在 **case** 之上不影响匹配:
    function f(n){
    switch (n) {
    case 2:
      console.log(2);
      break;
    default:
      console.log('default')
      break;
    case 1:  
      console.log('1');
      break;
    }
    }
    f(1); // 1
    f(2); // 2
    f(3); // default
    • switch 语句中存在 let / const重复声明问题:
      // 以下定义会报错
      function f(n){
      switch(n){
      case 1:
          let msg = 'hello';
          console.log(1);
          break;
      case 2: 
          let msg = 'leo';
          break;
      default: 
          console.log('default');
          break;
      }
      }
      // Error: Uncaught SyntaxError: Identifier 'msg' has already been declared

      这是由于两个 let 处于同一个块级作用域,所以它们被认为是同一变量名的重复声明。 解决方式,只需要将 case 语句包装在括号内即可解决:

      function f(n){
      switch(n){
      case 1:{ // added brackets
          let msg = 'hello';
          console.log(msg);
          break;
      }
      case 2: {
          let msg = 'leo';
          console.log(msg);
          break;
      }
      default: 
          console.log('default');
          break;
      }
      }

十四、函数

函数可以让一段代码被多次调用,避免重复代码。 如之前学习到的一些内置函数: alert(msg) / prompt(msg, default) / confirm(quesyion) 等。

1. 函数定义

定义函数有两种方式:函数声明函数表达式

1.1 函数声明

如定义一个简单 getUser 函数:

function getUser(name){
    return 'hello ' + name;
}
getUser('leo"); // 函数调用

通过函数声明来定义函数时,需要由以下几部分组成:

1.2 函数表达式

类似声明变量,还是以 getUser 为例:

let getUser = function(name){
    return 'hello ' + name;
}

另外,函数表达式也可以提供函数名,并用于函数内部指代函数本身:

let fun = function f(n){
    return n < 3 ? 1 : n * f(n - 1);
}
fun(3);  // 3
fun(5);  // 60

2. 函数调用

当定义一个函数后,它并不会自动执行,而是需要使用函数名称进行调用,如上面例子:

fun(3);  // 3

只要注意: 使用 函数表达式 定义函数时,调用函数的方法必须写在定义之后,否则报错:

console.log(fun());  // Uncaught ReferenceError: fun is not defined
let fun = function(){return 1};

而使用 函数声明 则不会出现该问题:

console.log(fun());  // 1
function fun(){return 1};

原因就是:函数提升仅适用于函数声明,而不适用于函数表达式。

3. 函数中的变量

在函数中,可以使用局部变量和外部变量。

3.1 局部变量

函数中声明的变量只能在该函数内可见。

let fun = function(){
    let name = 'leo';
}
fun();
console.log(name); // Uncaught ReferenceError: name is not defined

3.2 全局变量

函数内可以使用外部变量,并且可以修改外部变量的值。

let name = 'leo';
let fun = function(){
    let text = 'Hello, ' + name;
  console.log(text);
}
fun(); // Hello, leo

当函数内也有与外部变量名称相同的变量,会忽略外部变量:

let name = 'leo';
let fun = function(){
  let name = 'pingan8787';
    let text = 'Hello, ' + name;
  console.log(text);
}
fun(); // Hello, pingan8787

4. 函数参数

从ECMAScript 6开始,有两个新的类型的参数:默认参数,剩余参数。

4.1 默认参数

若函数没有传入参数,则参数默认值为undefined,通常设置参数默认值是这样做的:

// ES6 之前,没有设置默认值
function f(a, b){
    b = b ? b : 1;
    return a * b;
}
f(2,3);  // 6
f(2);    // 2
// ES6,设置默认值
function f(a, b = 1){
    return a * b;
}
f(2,3);  // 6
f(2);    // 2

4.2 剩余参数

可以将参数中不确定数量的参数表示成数组,如下:

function f (a, ...b){
    console.log(a, b);
}
f(1,2,3,4); // a => 1 b => [2, 3, 4]

既然讲到参数,那就不能少了 arguments 对象。

4.3 arguments 对象

函数的实际参数会被保存在一个类似数组的arguments对象中。在函数内,我们可以使用 arguments 对象获取函数的所有参数:

let fun = function(){
    console.log(arguments);
    console.log(arguments.length);
}
fun('leo'); 
// Arguments ["leo", callee: ƒ, Symbol(Symbol.iterator): ƒ] 
// 1

以一个实际示例介绍,实现将任意数量参数连接成一个字符串,并输出的函数:

let argumentConcat = function(separator){
    let result = '', i;
  for(i = 1; i < arguments.length; i ++){
    result += arguments[i] + separator;
  }
  return result;
}
argumentConcat(',', 'leo', 'pingan'); //"leo,pingan,"

5. 函数返回值

在函数任意位置,指定 return 指令来停止函数的执行,并返回函数指定的返回值。

let sum = function(a, b){
    return a + b;
};
let res = sum(1, 2);
console.log(res); // 3

默认空值的 return 或没有 return 的函数返回值为 undefined

十五、函数表达式

函数表达式是一种函数定义方式,在前面章节中已经介绍到了,这个部分将着重介绍 函数表达式函数声明 的区别:

1. 语法差异

// 函数表达式
let fun = function(){};
// 函数声明
function fun(){}

2. 创建时机差异

函数表达式会在代码执行到达时被创建,并且仅从那一刻可用。 而函数声明被定义之前,它就可以被调用。

// 函数表达式
fun();  // Uncaught ReferenceError: fun is not defined
let fun = function(){console.log('leo')};
// 函数声明
fun();  // "leo"
function fun(){console.log('leo')};

3. 使用建议

建议优先考虑函数声明语法,它能够为组织代码提供更多灵活性,因为我们可以在声明函数前调用该函数。

十六、箭头函数

本章节简单介绍箭头函数基础知识,后面章节会完整介绍。 函数箭头表达式是ES6新增的函数表达式的语法,也叫胖箭头函数,变化:更简洁的函数和this

1. 代码更简洁

// 有1个参数
let f = v => v;
// 等同于
let f = function (v){return v};
// 有多个参数
let f = (v, i) => {return v + i};
// 等同于
let f = function (v, i){return v + i};
// 没参数
let f = () => 1;
// 等同于
let f = function (){return 1};
let arr = [1,2,3,4];
arr.map(ele => ele + 1);  // [2, 3, 4, 5]

2. 注意点

  1. 箭头函数不存在this
  2. 箭头函数不能当做构造函数,即不能用new实例化;
  3. 箭头函数不存在arguments对象,即不能使用,可以使用rest参数代替;
  4. 箭头函数不能使用yield命令,即不能用作Generator函数。 一个简单的例子:
    function Person(){
    this.age = 0;
    setInterval(() => {
    this.age++;
    }, 1000);
    }
    var p = new Person(); // 定时器一直在执行 p的值一直变化

总结

本文作为《初中级前端 JavaScript 自测清单》第一部分,介绍的内容以常用基础知识为主,并在学习资料中,将知识点结合实际开发中遇到的场景进行展开介绍。希望能帮助大家自测自己的 JavaScript 水平并查缺补漏,温故知新。

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推荐 https://github.com/pingan8787/Leo_Reading/issues
ES小册 js.pingan8787.com
语雀知识库 Cute-FrontEnd

bg