当前位置: 首页 > article >正文

【H2O2|全栈】JS入门知识(五)

目录

JS

前言

准备工作

数组API(一)

API概念

数组常见API(一)

arguments

作用域

概念

全局作用域

局部作用域

块级作用域

变量的作用域

作用域链

案例

预解析

概念

变量预解析

函数预解析

案例

对象

概念

优点

属性和属性值

创建对象

遍历对象

结束语


JS

前言

本系列博客主要分享JavaScript的基础语法知识,本期为第五期,包含一些简单的js语法。今天的内容主要包括数组的常用API,作用域,变量,预解析以及对象的相关内容。

与HTML和CSS相比,JS加入了很多逻辑性的元素在里面,所以需要一定的逻辑思维能力,要求能够整合一些知识。如果遇到不理解之处,可以参阅同系列之前的章节。

准备工作

软件:【参考版本】Visual Studio Code

插件(扩展包):Open in browser, Live Preview, Live Server, Tencent Cloud AI Code Assistant, htmltagwrap

浏览器版本:Chrome

系统版本: Win10/11/其他非Windows版本

*我的电脑是Win10的版本,仅供参考*

数组API(一)

API概念

API,英文全称为Application Programming Interface,即应用程序编程接口。 

通常来说,API是软件系统中的一组预定义函数、协议或规则,用于不同软件应用程序之间的通信和数据交换

之前我们知道,可以使用  arr.length  调用数组的长度,类似的,我们也可以使用相同的方式调用数组的API。

不过需要注意,API通常为函数或者方法,因此在调用时不要忘记小括号和必要的参数(如果有)。

数组常见API(一)

今天主要来讲部分常用的数组API,先列在表格里——

API作用
splice(index, number)在数组的index位置开始删除number个元素
splice(index, number, content)在数组的index位置开始删除number个元素,并且替换上content的内容
unshift(item)在数组开头增加指定元素
shift()在数组开头删除一个元素
push(item)压栈,即在数组的末尾增加指定元素
pop()弹栈,即在数组的末尾删除一个元素
slice(start, end)从数组中截取指定左闭右开区间(索引)内的元素
arr1.concat(arr2)在指定的数组的末尾拼接另一个数组
join("separator")将数组转化为字符串,并且在元素之间添加分隔符separator
sort()默认升序排序,元素有多个字符时,取数组元素的第一个字符进行排序

sort(function(a, b) {

        return a - b

})

内置匿名函数进行排序,以 a - b 为正值设置升序排序,此时 b - a 为负值,即设置降序排序
reverse()将数组内容翻转

arguments

arguments是一种类数组,它有数组的索引和长度,但是没有数组的API。

在函数中,arguments是默认有的,可以用来接收任意长度的数组。

作用域

概念

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。

作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突

在es6之前,JS有两种作用域——全局作用域局部作用域

在es6之后,还有一种作用于 {} 内的作用域——块级作用域

全局作用域

全局作用域指的是所有代码执行的所在的整个环境,通常来说,这个环境是window

局部作用域

局部作用域指的是作用于函数内部的代码环境,所以也可以叫函数作用域。

块级作用域

{} 内定义的某些变量,我们希望它只在 {} 中使用,即在块级作用域里使用。

在es6中,使用let和const声明定义的变量,只能在 {} 中使用。

常见的块级作用域有  if()  for()  等。

变量的作用域

根据作用域的不同,变量可以分为两种——全局变量局部变量

全局变量在代码的任何位置都可以使用,在全局作用域下 var 声明的变量都是全局变量。

特殊情况下,在函数内不使用 var 声明的变量也是全局变量(写法不规范,所以不建议使用)。

局部变量只能在该函数内部使用,在函数内部 var 声明的变量是局部变量。

函数的形参实际上就是一种局部变量。

两类变量的区别是:

  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

作用域链

如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;

根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链

作用域链的原则为就近原则,即选取最近的元素作为当前使用的元素。

案例

Q:现在,有下面这串代码——

var a = 1;
var b = '11';
function fn1() {
    var a = 2;
    var b = '22';
    fn2();
    function fn2() {
        var a = 3;
        fn3();
        function fn3() {
            var a = 4;
            console.log(a); //a的值 ?
            console.log(b); //b的值 ?
        }
    }
}
fn1();

请问输出的a和b的值是多少?

A:我们使用一张图来分析上述代码的作用域链——

所以,输出应当是4和'22'。

Q:对于下面的代码,输出的值应当是多少?

var a = 10

function fn1() {
    var a = 20
    fn2()
}

function fn2() {
    console.log(a)
}

A:对于  fn2()  而言,虽然它在  fn1()  中被调用了,但是实际上它是被声明在全局中的,所以作用域是window,因此输出值为10。

预解析

概念

JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。

JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析代码执行

  • 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义,预解析也叫做变量提升函数提升
  • 代码执行: 从上到下执行JS语句。

注意:预解析会把变量和函数的声明在代码执行之前执行完成。

变量预解析

变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升

函数预解析

函数的声明会被提升到当前作用域的最上面,但是不会调用函数。

案例

Q:对于下面的代码,输出的结果是什么?

console.log(num)
var num = 10

fn1()
function fn1() {
    console.log('打印')
}

fn2()
var fn2 = function() {
    console.log('想不到吧')
}

A:由于变量的值不会提升,所以第一个是默认var num但是未赋值,结果为输出undefined

由于命名函数可以提升,相当于在fn1()之前实质上已经声明函数并在该语句完成调用,结果为输出打印

匿名函数相当于变量,该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用,结果为报错 fn is not a function

对象

概念

在 JavaScript 中,对象是一组无序的相关属性方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。

  • 属性:事物的特征,在对象中用属性来表示(常用名词表示)
  • 方法:事物的行为,在对象中用方法(函数)来表示(常用动词表示)

以一部手机为对象,那么它的属性和方法应当是——

优点

保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组。

如果要保存一个人的完整信息呢?

例如,将“张三”的个人的信息保存在数组中的方式为——

var arr = [‘张三’, ‘男', 128, 154]

上述例子中用数组保存数据的缺点是:数据只能通过索引值访问,开发者需要清晰的清除所有的数据的排行才能准确地获取数据,而当数据量庞大时,不可能做到记忆所有数据的索引值。

为了让更好地存储一组数据,对象应运而生:对象中为每项数据设置了属性名称,可以访问数据更语义化,数据结构清晰,表意明显,方便开发者使用。

如果使用对象来表述上述信息,应当如下——

var obj = {
    "name":"张三",
    "sex":"男",
    "age":128,
    "height":154
}

属性和属性值

对象中包含了表达这个具体事物(对象)的属性和方法,采取键值对的形式表示。

  • 键:相当于属性名,即对象中存储具体数据的项
  • 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等),对象方法即对象中存储函数的项

比如,之前在为张三设置名字属性时,使用的就是下面的键值对——

name: "张三",

这里也给一个值为函数的情况吧——

sayHello : function(){
        alert('大家好啊~');
    }

访问对象的属性

  • 对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“ 的 ”
  • 对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号 

示例代码如下——

console.log(obj.name)     // 调用名字属性
console.log(obj['name'])  // 调用名字属性

调用对象的方法

  • 对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
  • 也可以利用函数名调用

示例代码如下——

obj.fn()
obj["fn"]()

小结

属性是对象的一部分,而变量不是对象的一部分,变量是单独存储数据的容器

  • 变量:单独声明赋值,单独存在
  • 属性:对象里面的变量称为属性,不需要声明

方法是对象的一部分,函数是单独封装操作的容器

  • 函数:单独存在的,通过“函数名()”的方式就可以调用
  • 方法:对象里面的函数称为方法,方法不需要声明,使用“对象.方法名()”的方式就可以调用 

创建对象

创建对象通常来说有三种方式——字面量new构造函数

使用字面量创建

使用字面量创建的参考代码如下——

var obj1 = {}

这种方式在创建时即可添加属性和属性值,示例代码如下——

var obj = {
    name : 'pink',
    age : 18,
    sex : '男',
    sayHello : function(){
        alert('大家好啊~');
    }
};

使用new Object()创建

该方式用于创建一个空的对象,参考代码如下——

var obj2 = new Object();

实质上,Object()内置了一个构造函数,利用构造函数创建了一个新对象。

为该方法创建的对象赋值的方法示例如下——

obj2.name = 'pink';
obj2.age = 18;
obj2.sex = '男';
obj2.sayHello = function(){
    alert('大家好啊~');
}

注意以下三个要点:

  • Object() :第一个字母大写
  • new Object() :需要 new 关键字
  • 使用的格式:对象.属性 =  值;

使用构造函数创建

构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

使用构造函数的封装格式如下——

function 构造函数名(形参1,形参2,形参3) {
     this.属性名1 = 参数1;
     this.属性名2 = 参数2;
     this.属性名3 = 参数3;
     this.方法名 = 函数体;
}

使用构造函数调用的参考代码如下——

var obj3 = new 构造函数名(实参1,实参2,实参3)

以上代码中,obj即接收到构造函数创建出来的对象。

注意事项

  • 构造函数约定首字母大写
  • 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
  • 构造函数中不需要 return 返回结果
  • 当我们创建对象的时候,必须用 new 来调用构造函数
  • 构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class);创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化 

new关键字的作用

  • 在构造函数代码开始执行之前,创建一个空对象;
  • 修改this的指向,把this指向创建出来的空对象;
  • 执行函数的代码
  • 在函数完成之后,返回this---即创建出来的对象  

遍历对象

for...in 语句用于对数组或者对象的属性进行循环操作。

示例代码如下——

for (变量 in 对象名字) {
    // 在此执行代码
}

语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key

遍历对象获取属性和属性值的示例代码如下——

for (var k in obj) {
    console.log(k);      // 这里的 k 是属性名
    console.log(obj[k]); // 这里的 obj[k] 是属性值
}

扩充知识

我们知道,数组实质上也是一种对象,所以我们也可以用相同的 for ... in 方式对数组进行遍历——

for (var i in arr) {
    console.log(arr[i])
}

此时的i是索引值

此外,我们还可以使用 for ... of 方式对数组进行遍历——

for (var item in arr) {
    console.log(item)
}

此时的item是数组中的元素

结束语

本期的内容到这里就结束了,主要是js的数组的常用API,作用域,预解析以及对象的相关内容。在后续的本系列博客中,我会继续更新js的基础语法知识,并适当地配合上一些案例。

在全栈领域,博主也只不过是一个普通的萌新而已。本系列的博客主要是记录一下自己学习的一些经历,然后把自己领悟到的一些东西总结一下,分享给大家。

文章全篇的操作过程都是笔者亲自操作完成的,一些定义性的文字加入了笔者自己的很多理解在里面,所以仅供参考。如果有说的不对的地方,还请谅解。

==期待与你在下一期博客中再次相遇==

——还在漏气的【H2O2】


http://www.kler.cn/news/359505.html

相关文章:

  • 前端报错:‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序(node_modules下载不下来)
  • 中小型医院网站开发:Spring Boot入门
  • Mac 查看编译器默认使用C++标准
  • C语言【调试】(个人笔记版)
  • 【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第五篇-着色器投影-投射阴影部分】
  • 选择排序,插入排序,快速排序的java简单实现
  • 200台设备如何做到运行半年0故障?工厂设备管理这些环节是关键!
  • Yolov10训练的餐盘菜品目标检测软件(包含源码及数据集)
  • B3612 【深进1.例1】求区间和
  • JVM篇(学习预热 - JVM正式展开 - (实战课程学习总结))(持续更新迭代)
  • Go 设置并发控制数量 【go并发模型】
  • nfs 中 lockd 与 statd 的作用
  • 终于找到了!Ubuntu 虚拟机卡死的终极解决方案(如何解决VMware安装Ubuntu24.04桌面进不去、黑屏、虚拟机卡死、显示不全、屏幕闪烁等问题)
  • 10月20日
  • Docker报错-Docker Desktop - Unexpected WSL error
  • [while循环]k的幂
  • 如何利用CMMI帮助组织消除低价值流程
  • 深入理解 Netty 中的 Unpooled 使用方法
  • LeetCode Hot100 | Day4 | 层序遍历有序数组转搜索树验证搜索树搜索树中第K小的元素
  • 如何查看python安装了哪些包