JavaScript对象
JavaScript对象
- Object类型,我们也称为一个对象。是JavaScript中的引用数据类型
- 它是一种复合值,它将很多值聚合到一起,可以通过名字访问这些值
- 对象也可以看做是属性的无序集合,每个属性都是一个key/value对
- 对象除了可以创建自有属性,还可以通过从一个名为原型的对象那里继承属性
- 除了字符串、数字、
true
、false
、null
和undefined
之外,JS中的值都是对象
创建对象
创建对象有两种方式:
// 第一种
var person = new Object();
person.name = "孙悟空";
person.age = 18;
// 第二种
var person = {
name:"孙悟空",
age:18
};
对象属性
访问属性的两种方式
var person = new Object();
person.name = "孙悟空";
person.age = 18;
// 对象.属性名
var name = person.name
// 对象['属性名']
var age = person['age']
向对象中添加属性
语法:
对象.属性名 = 属性值
对象["属性名"] = 属性值
对象的属性名没有任何要求,不需要遵守标识符的规范,但是在开发中,尽量按照标识符的要求去写。属性值也可以任意的数据类型。
读取对象中的属性
语法:
对象.属性名
对象["属性名"]
如果读取一个对象中没有的属性,它不会报错,而是返回一个undefined
枚举对象中的属性
for...in 语法:
for(var 属性名 in 对象){
}
for...in语句的循环体会执行多次,对象中有几个属性就会执行几次,每次将一个属性名赋值给我们定义的变量,我们可以通过它来获取对象中的属性
删除对象中的属性
语法:
delete 对象.属性名
delete 对象["属性名"]
使用in检查对象中是否含有指定属性
语法:"属性名" in 对象
如果在对象中含有该属性,则返回true如果没有则返回false
使用对象字面量,在创建对象时直接向对象中添加属性
语法:
var obj = {
属性名:属性值,
属性名:属性值,
属性名:属性值,
属性名:属性值
}
基本数据类型与引用数据类型
- JS中的变量可能包含两种不同数据类型的值:基本数据类型和引用数据类型
- JS中一共有5种基本数据类型:
String
、Number
、Boolean
、Undefined
、Null
- 基本数据类型的值是无法修改的,是不可变的
- 基本数据类型的比较是值的比较,也就是只要两个变量的值相等,我们就认为这两个变量相等
- 引用类型的值是保存在内存中的对象
- 当一个变量是一个对象时,实际上变量中保存的并不是对象本身,而是对象的引用
- 当从一个变量向另一个变量复制引用类型的值时,会将对象的引用复制到变量中,并不是创建一个新的对象
- 这时,两个变量指向的是同一个对象。因此,改变其中一个变量会影响另一个
栈和堆
- JavaScript在运行时数据是保存到栈内存和堆内存当中的
- 简单来说栈内存用来保存变量和基本类型。堆内存用来保存对象
- 我们在声明一个变量时实际上就是在栈内存中创建了一个空间用来保存变量
- 如果是基本类型则在栈内存中直接保存
- 如果是引用类型则会在堆内存中保存,变量中保存的实际上对象在堆内存中的地址
函数
- 函数是由一连串的子程序(语句的集合)所组成的,可以被外部程序调用。向函数传递参数之后,函数可以返回一定的值
- 通常情况下,JavaScript代码是自上而下执行的,不过函数体内部的代码则不是这样。如果只是对函数进行了声明,其中的代码并不会执行。只有在调用函数时才会执行函数体内部的代码
- 这里要注意的是JavaScript中的函数也是一个对象
- 函数也是一个对象,所以函数和其他对象一样也可以作为一个参数传递给另外一个函数。
- 但是要注意的是使用函数作为参数时,变量后边千万不要加(),不加()表示将函数本身作为参数,加上以后表示将函数执行的结果作为参数。
- 函数对象的方法
每个函数都有两个方法call()和apply(),call()和apply()都可以指定一个函数的运行环境对象,换句话说就是设置函数执行时的this值。
函数对象.call(this对象,参数数组)
函数对象.apply(this对象,参数1,参数2,参数N)
函数的声明
-
首先明确一点函数也是一个对象,所以函数也是在堆内存中保存的
-
函数声明比较特殊,需要使用
function
关键字声明// 函数表达式 var sum = function(a,b){return a+b};
-
上边的例子就是创建了一个函数对象,并将函数对象赋值给了sum这个变量。其中()中的内容表示执行函数时需要的参数,{}中的内容表示函数的主体
// 函数声明
function 函数名([形参1,形参2...形参N]){
// 语句...
}
函数的调用
- 调用函数时,传递给函数的参数称为实参(实际参数)。
- 如果想调用我们上边定义的sum函数,可以这样写:
var result = sum(123,456);
这样表示调用sum这个函数,并将123和456作为实参传递给函数,函数中会将两个参数求和并赋值给result
传递参数
JS中的所有的参数传递都是按值传递的。也就是说把函数外部的值赋值给函数内部的参数,就和把值从一个变量赋值给另一个变量是一样的。
形参和实参
-
形参:形式参数
定义函数时,可以在()中定义一个或多个形参,形参之间使用,隔开定义形参就相当于在函数内声明了对应的变量但是并不赋值,形参会在调用时才赋值。
-
实参:实际参数
调用函数时,可以在()传递实参,传递的实参会赋值给对应的形参,调用函数时JS解析器不会检查实参的类型和个数,可以传递任意数据类型的值。如果实参的数量大于形参,多余实参将不会赋值,如果实参的数量小于形参,则没有对应实参的形参将会赋值
undefined
函数内部属性
在函数内部,有两个特殊的对象:
- arguments
- 该对象实际上是一个数组,用于保存函数的参数
- 同时该对象还有一个属性callee来表示当前函数
- this
- this引用的是一个对象。对于最外层代码与函数内部的情况,其引用目标是不同的。
- 此外,即使在函数内部,根据函数调用方式的不同,引用对象也会有所不同。需要注意的是,
this
引用会根据代码的上下文语境自动改变其引用对象
this 引用的规则
- 在最外层代码中,
this
引用的是全局对象。 - 在函数内,
this
根据函数调用方式的不同而有所不同:
函数的调用方式 | this引用的对象 |
---|---|
构造函数 | 所生成的对象 |
调用对象的方法 | 当前对象 |
apply或call调用 | 参数指定的对象 |
其他方式 | 全局对象(window) |
作用域
作用域简单来说就是一个变量的作用范围。
在JS中作用域分成两种:
- 全局作用域
- 直接在
script
标签中编写的代码都运行在全局作用域中 - 全局作用域在打开页面时创建,在页面关闭时销毁
- 全局作用域中有一个全局对象
window
,window
对象由浏览器提供,可以在页面中直接使用,它代表的是整个的浏览器的窗口 - 在全局作用域中创建的变量都会作为
window
对象的属性保存在全局作用域中创建的函数都会作为window
对象的方法保存 - 在全局作用域中创建的变量和函数可以在页面的任意位置访问。在函数作用域中也可以访问到全局作用域的变量。
- 尽量不要在全局中创建变量
- 直接在
- 函数作用域
- 函数作用域是函数执行时创建的作用域,每次调用函数都会创建一个新的函数作用域
- 函数作用域在函数执行时创建,在函数执行结束时销毁
- 在函数作用域中创建的变量,不能在全局中访问
- 当在函数作用域中使用一个变量时,它会先在自身作用域中寻找,如果找到了则直接使用,如果没有找到则到上一级作用域中寻找,如果找到了则使用,找不到则继续向上找,一直会
- 变量的声明提前
- 在全局作用域中,使用
var
关键字声明的变量会在所有的代码执行之前被声明,但是不会赋值。所以我们可以在变量声明前使用变量。但是不使用var
关键字声明的变量不会被声明提前。 - 在函数作用域中,也具有该特性,使用
var
关键字声明的变量会在函数所有的代码执行前被声明,如果没有使用var
关键字声明变量,则变量会变成全局变量
- 在全局作用域中,使用
- 函数的声明提前
- 在全局作用域中,使用函数声明创建的函数(
function fun(){}
),会在所有的代码执行之前被创建,也就是我们可以在函数声明前去调用函数,但是使用函数表达式(var fun = function(){}
)创建的函数没有该特性 - 在函数作用域中,使用函数声明创建的函数,会在所有的函数中的代码执行之前就被创建好了
- 在全局作用域中,使用函数声明创建的函数(
闭包(closure)
- 闭包是JS一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。因为函数是JS中唯一拥有自身作用域的结构,因此闭包的创建依赖于函数
- 也可以将闭包的特征理解为,其相关的局部变量在函数调用结束之后将会继续存在
构造函数
- 构造函数是专门用来创建对象的函数
- 一个构造函数我们也可以称为一个类
- 通过一个构造函数创建的对象,我们称该对象时这个构造函数的实例
- 通过同一个构造函数创建的对象,我们称为一类对象
- 构造函数就是一个普通的函数,只是他的调用方式不同,如果直接调用,它就是一个普通函数,如果使用new来调用,则它就是一个构造函数
- 每个对象中都有一个
constructor
属性,它引用了当前对象的构造函数
例子:
function Person(){
}
new关键字
- 使用new关键字执行一个构造函数时:
- 首先,会先创建一个空的对象
- 然后,会执行相应的构造函数。构造函数中的
this
将会引用这个新对象 - 最后,将对象作为执行结果返回
- 构造函数总是由new关键字调用
- 构造函数和普通函数的区别就在于调用方式的不同
- 任何函数都可以通过new来调用,所以函数都可以是构造函数
- 在开发中,通常会区分用于执行的函数和构造函数
- 构造函数的首字母要大写
instanceof关键字
instanceof 用来检查一个对象是否是一个类的实例
语法:对象 instanceof 构造函数
- 如果该对象是构造函数的实例,则返回
true
,否则返回false
Object
是所有对象的祖先,所以任何对象和Object
做instanceof
都会返回true
垃圾回收
- 不再使用的对象的内存将会自动回收,这种功能称作垃圾回收。
- 所谓不再使用的对象,指的是没有被任何一个属性(变量)引用的对象。
- 垃圾回收的目的是,使开发者不必为对象的生命周期管理花费太多精力。
原型
- JS是一门面向对象的语言,而且它还是一个基于原型的面向对象的语言
- 所谓的原型实际上指的是,在构造函数中存在着一个名为原型的(prototype)对象,这个对象中保存着一些属性,凡是通过该构造函数创建的对象都可以访问存在于原型中的属性
- 最典型的原型中的属性就是toString()函数,实际上我们的对象中并没有定义这个函数,但是却可以调用,那是因为这个函数存在于Object对应的原型中
- 创建一个构造函数以后,解析器都会默认在函数中添加一个prototype,prototype属性指向的是一个对象,这个对象我们称为原型对象。
- 它所创建的对象中都会有一个隐含的属性执行该原型对象。这个隐含的属性可以通过对象.__proto__来访问。
- 原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。我们可以将对象中共有的属性和方法统一添加到原型对象中,这样我们只需要添加一次,就可以使所有的对象都可以使用。
- 当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找,如果在自身中找到了,则直接使用。如果没有找到,则去原型对象中寻找,如果找到了则使用,如果没有找到,则去原型的原型中寻找,依此类推。直到找到Object的原型为止,Object的原型的原型为null,如果依然没有找到则返回undefined
- hasOwnProperty()
- 这个方法可以用来检查对象自身中是否含有某个属性
- 语法:对象.hasOwnProperty("属性名")
获取原型对象的方法
除了可以通过构造函数获取原型对象以外,还可以通过具体的对象来获取原型对象。
Object.getPrototypeOf(对象)
对象.proto
对象.constructor.prototype需要注意的是,我们可以获取到Object的原型对象,也可以对它的属性进行操作,但是我们不能修改Object原型对象的引用
数组
-
数组也是对象的一种
-
数组是一种用于表达有顺序关系的值的集合的语言结构
-
数组内的各个值被称作元素。每一个元素都可以通过索引(下标)来快速读取。索引是从零开始的整数
-
创建数组
var arr = new Array(); var arr = [];
-
向数组中添加元素
arr[0] = 123; arr[1] = "hello";
-
创建数组时直接添加元素
var arr = [123,"hello",true,null];
-
获取和修改数组的长度
- 使用length属性来操作数组的长度,获取长度:
数组.length
length
获取到的是数组的最大索引+1 - 修改数组的长度
数组.length = 新长度
,如果修改后的length大于原长度,则多出的部分会空出来,如果修改后的length小于原长度,则原数组中多出的元素会被删除
- 使用length属性来操作数组的长度,获取长度:
-
向数组的最后添加元素
数组[数组.length] = 值
-
数组的方法
push()
用来向数组的末尾添加一个或多个元素,并返回数组新的长度,语法:数组.push(元素1,元素2,元素N)
pop()
用来删除数组的最后一个元素,并返回被删除的元素unshift()
向数组的前边添加一个或多个元素,并返回数组的新的长度shift()
删除数组的前边的一个元素,并返回被删除的元素slice()
- 可以从一个数组中截取指定的元素
- 该方法不会影响原数组,而是将截取到的内容封装为一个新的数组并返回
- 参数:
- 截取开始位置的索引(包括开始位置)
- 截取结束位置的索引(不包括结束位置),第二个参数可以省略不写,如果不写则一直截取到最后
- 参数可以传递一个负值,如果是负值,则从后往前数
splice()
- 可以用来删除数组中指定元素,并使用新的元素替换,该方法会将删除的元素封装到新数组中返回
- 参数:
- 删除开始位置的索引
- 删除的个数
- 三个以后,都是替换的元素,这些元素将会插入到开始位置索引的前边
-
遍历数组
// 一般情况我们都是使用for循环来遍历数组: for(var i=0 ; i<数组.length ; i++){ //数组[i] } // 使用forEach()方法来遍历数组(不兼容IE8) 数组.forEach(function(value , index , obj){ // value:正在遍历的元素 // index:正在遍历元素的索引 // obj:被遍历对象 });
Date
- Date类型用来表示一个时间。
- Date采取的是时间戳的形式表示时间,所谓的时间戳指的是从1970年1月1日0时0秒0分开始经过的毫秒数来计算时间。
- 直接使用new Date()就可以创建一个Date对象。
- 创造对象时不传参数默认创建当前时间。可以传递一个毫秒数用来创建具体的时间。
- 也可以传递一个日期的字符串,来创建一个时间。
格式为:月份/日/年 时:分:秒
例如:06/13/2004 12:12:12
Math
- JS还为保存数学公式和信息提供了一个公共位置,即
Math
对象。 - 与我们在JavaScript直接编写的计算功能相比,
Math
对象提供的计算功能执行起来要快得多。Math
对象中还提供了辅助完成这些计算的属性和方法
Math对象的属性
属性 | 说明 |
---|---|
Math.E | 自然对数的底数,即常量 e 的值 |
Math.LN10 | 10的自然对数 |
Math.LN2 | 2的自然对数 |
Math.LOG2E | 以2为底 e 的对数 |
Math.LOG10E | 以10为底 e 的对数 |
Math.PI | π的值 |
Math.SQRT1_2 | 1/2的平方根(即2的平方根的倒数) |
Math.SQRT2 | 2的平方根 |
Math的方法
- Math.abs() 绝对值运算
- Math.ceil() 向上取整
- Math.floor() 向下取整
- Math.round() 四舍五入取整
- Math.random() 生成一个0-1之间的随机数
生成一个x-y之间的随机数示例示例:Math.round(Math.random()*(y-x)+x)
- Math.pow(x,y) 求x的y次幂
- Math.sqrt() 对一个数进行开方
- Math.max() 求多个数中最大值
- Math.min() 求多个数中的最小值
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异