目录
一、对象
JS中的数据类型:
基本数据类型:
String 字符串
Number 数值
Boolean 布尔值
Null 空值
Undefined 未定义
以上这五种数据类型属于基本数据类型,以后我们看到的值,只要不是这五种,全是对象。
引用数据类型:
Object 对象
1.1 对象简介
基本数据类型都是单一的值,值和值之间没有任何的联系。
如果使用基本数据类型的数据,我们所创建的变量都是独立的,不能成为一个整体。
对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性。
1.2 对象的分类
1. 内建对象
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如,Math String Number Function Object...
2. 宿主对象
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
- 比如BOM DOM (console document)
3. 自定义对象
- 由开发人员自己创建的对象
1.3 对象的基本操作
// 创建对象
let obj = new Object();
使用new关键字调用的函数,是构造函数constructor,构造函数是专门用来创建对象的函数。
使用typeof检查一个对象时,会返回object
在对象中保存的值称为属性
向对象添加属性
语法:对象.属性名 = 属性值;
obj.name = "piggy";
obj.gender = "male";
obj.age = 23;
读取对象中的属性
语法:对象.属性名
如果读取对象中没有的属性,不会报错,会返回undefined
修改对象的属性值
语法: 对象.属性名 = 新值
删除对象的属性
语法: delete 对象.属性名
1.4 属性名与属性值
向对象中添加属性
属性名
- 对象的属性名不强制要求遵守标识符的规范,但还是要尽量遵守
如果要使用特殊的属性名,不能采用.的方式来操作
需要使用另一种方式:
语法: 对象["属性名"] = 属性值
读取时也要采用这种方式,使用[]这种形式去操作属性,更加的灵活。
在[]中可以直接传递一个变量,这样变量值是多少就会读取那个值。
属性值
JS对象的属性值,可以是任意的数据类型。甚至也可以是一个对象
in 运算符
通过该运算符可以检测一个对象中是否含有指定的属性,如果有返回true,没有返回false
console.log("name" in obj);
JS中的变量都是保存到栈内存中的
基本数据类型的值直接在栈内存中存储,值与值之间是独立存在,修改一个变量不会影响另一个变量
对象的值是保存到堆内存中的,每创建一个新的对象,就会在堆内存中开辟出一个新的空间,二变量保存的是对象的内存地址,如果两个变量保存的是同一个对象引用,当一个通过一个变量修改属性时,另一个也会受到影响。
1.5 对象字面量
使用对象字面量来创建一个对象。
let obj = {};
使用对象字面量,可以在创建对象时,直接指定对象中的属性
语法: {属性名:属性值,属性名:属性值...}
let obj = {
age: 18,
name: "dog"
}
如果一个属性之后没有其他的属性了,就不要写,
1.6 函数
函数也是一个对象
1.6.1 简介
函数中可以封装一些功能(代码),在需要时可以执行这些功能。
函数中可以保存一些代码在需要时调用。
let fun = new Function():
可以将要封装的代码以字符串的形式传递给构造函数
封装到函数中的代码不会立即执行,函数中的代码会在函数调用时执行
调用函数
语法: 函数对象()
fun();
当调用函数时,函数中封装的代码会按照顺序执行。
使用函数声明来创建一个函数
function 函数名([形参1,形参2,...]) {
语句...
}
function fun2() {
console.log(111);
}
使用函数表达式来创建一个函数
let 函数名 = function([形参1,形参2,...]) {
语句...
}
1.6.2 函数的参数
可以在函数的()中来指定一个或多个形参,多个形参之间使用,隔开,声明形参就相当于在函数内部声明了对应的变量。
调用函数时,不会检查实参的类型,所以要注意是否会接收到非法的参数,有时需要进行检查
调用函数时,解析器也不会检查实参的数量,多余实参不会被赋值。
如果实参的数量少于形参的数量,则没有实参的形参将会是undefined
1.6.3 函数的返回值
可以使用return来设置函数的返回值
语法:
function sum(a, b) {
let d = a + b;
return d;
}
return后的值将会作为函数的执行结果返回,可以定义一个变量,来接收结果。
在函数中,return后面的代码都不会被执行。
如果return后面不跟任何值,或者不写return都会返回undefined,return可以返回任何类型的值
实参可以是任意的数据类型,也可以是一个对象。当我们的参数过多时,可以将参数打包进一个对象。
函数同样也可以作为参数。
函数名 函数名()一个是函数对象,一个是调用函数。
return返回值可以是任何类型,也可以是对象、函数。
1.6.4 立即执行函数
(function(a, b) {
alert(a + b);
})(1, 2);
1.7 方法
函数也可以称为对象的属性,如果一个函数作为对象的属性保存,那么我们称这个函数为这个对象的方法,调用函数就说是调用对象的方法(method)。
枚举对象中的属性
for(let 变量 in 对象) {
}
let obj = {
name: "123";
age: 12;
gender: "34"
}
for (let n in obj) {
console.log(n);
console.log(obj[n]);
}
for...in...语句有几个属性,循环体就执行几次。
1.8 作用域
作用域指一个变量的作用的范围。
在JS中一共有两种作用域:全局作用域和函数作用域
1.8.1 全局作用域
直接编写在script标签中的JS代码,都在全局作用域。全局作用域在页面打开时创建,关闭时销毁。
在全局作用域中,有一个全局对象window,它代表的是一个浏览器的窗口,它由浏览器创建,我们可以直接使用。
在全局作用域中,我们创建的对象,都会作为window对象的属性保存。
let a = 10;
console.log(window.a); // 10
创建的函数都会作为window的方法保存。
function fun() {
console.log(1);
}
window.fun() // 1
变量的声明提前:
使用let关键字声明的变量,会在所有代码执行之前被声明。但是如果声明变量时不使用关键字,则变量不会被声明提前。
函数的声明提前:
使用函数声明形式创建的函数function()在所有代码执行之前就被创建,所以我们可以在函数声明前调用函数。
// 函数声明,会被提前创建
function fun01() {
console.log(1);
}
// 函数表达式,不会被提前创建
let fun02 = function() {
console.log(2);
}
全局作用域中的变量都是全局变量,在页面的任意位置都可以访问到。
1.8.2 函数作用域
调用函数时,创建函数作用域,执行完毕后,函数作用域销毁。
每调用一次函数,就会创建一个新的函数作用域,他们之间是相互独立的。
在函数作用域中,可以访问到全局作用域的变量。但是全局作用域无法访问到函数作用域的变量。
当在函数作用域中操作一个变量时,会现在自身作用域中寻找,如有,直接使用,若无,到上一级寻找。若依旧未找到,则报错ReferenceError。
let a = 10;
function fun() {
a = 20;
function fun2() {
console.log(a); // 20
console.log(window.a); // 10
}
}
在函数中访问全局变量,可以使用window。
1.9 this
浏览器(解析器)在调用函数时,每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this。
this指向的是一个对象,这个对象我们称为函数执行的上下文对象,根据函数的调用方式的不同,this会指向不同的对象。
以函数的形式调用,this指向的是window;以方法的形式调用,this指向的就是那个对象。
let name = "全局";
function fun() {
console.log(this.name):
}
let obj = {
name: "swk",
sayName: fun
};
let obj2 = {
name: "shs",
sayName: fun
};
obj.sayName() // "swk"
obj2.sayName() // "shs"
1.10 使用工厂方法创建对象
let obj1 = {
name: "swk",
age: 18,
gender: "male",
sayName: funvtion() {
console.log(this.name);
}
};
let obj2 = {
name: "zbj",
age: 28,
gender: "male",
sayName: funvtion() {
console.log(this.name);
}
};
let obj3 = {
name: "shs",
age: 38,
gender: "male",
sayName: funvtion() {
console.log(this.name);
}
};
function createPerson(name, age, gender) {
let obj = new Object();
// 向对象中添加属性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function() {
console.log(this.name);
};
return obj;
}
let obj2 = createPerson("swk", 18, "male");
1.11 构造函数
使用工厂方法创建的对象,使用的构造函数都是Object,所以创建的对象都是Object这个类型,就导致我们无法区分多种不同类型的对象。
创建一个构造函数,专门用来创建***对象。
构造函数就是一个普通的函数,创建方式没有区别,与普通函数的区别在于调用方式的不同,普通函数直接调用,而构造函数需要使用new关键字来调用。同时,构造函数函数名首字母需要大写。
构造函数的执行流程
1. 立刻创建一个新的对象
2. 将新建的对象设置为函数中的this,在构造函数中可以使用this引用新创建的对象
3. 逐行执行函数中的代码
4. 将新建的对象作为返回值返回
使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function() {
console.log(this.name);
};
}
let per = new Person("swk", 18, "male");
instanceof
使用instanceof可以检查一个对象是否是一个类的实例
语法:
对象 isinstanceof 构造函数
console.log(per isinstanceof Person); // true
如果是,返回true,不是,返回false
所有的对象都是Object的后代。
this的情况:
1. 当以函数的形式调用时,this是window
2. 当以方法调用时,谁调用方法,this就是谁
3. 当以构造函数的形式调用时,this就是新创建的那个对象
在Person构造函数中,为每一个对象都添加了一个sayName方法,目前我们的方法是在构造函数内部创建的,也就是构造函数每执行一次就会创建一个sayName方法,也就是所有实例的sayName都是唯一的,这样就导致了构造函数执行一次就会创建一个新的方法,执行1000次就会创建1000个新的方法。这是完全没有必要的,完全可以使所有的对象共享同一个方法。
可以将函数方法定义在全局作用域中。
1.12 原型对象
将函数定义在全局作用域,会污染全局作用域的命名空间,而且定义在全局作用域中也不安全。
原型prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype。
这个属性对应着一个对象,这个对象就是原型对象。
如果函数作为普通函数调用,prototype没有任何作用;
当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向构造函数的原型对象,我们可以通过__proto__来访问该属性。
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.sayName = function() {
console.log(this.name(;
};
以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到函数的原型对象中,这样就不用分别为每个对象添加,也不会影响到全局作用域,就可以使这些对象拥有这些属性和方法。
使用in检查对象中是否有某个属性时,如果对象中没有但是原型中有也会返回true。
hasOwnProperty()
可以使用对象的hasOwnProperty()来检查对象自身中是否含有该属性,使用该方法只有当对象自身中含有属性时,才会返回true。
原型对象也是对象,所以它也有原型。当我们使用一个对象的属性或对象时,会在自身中寻找,如果有,直接使用,如果自身没有,去原型对象中寻找,如有直接使用,若没有,去原型对象的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined。
1.13 垃圾回收
程序运行过程中会产生垃圾,这些垃圾多了以后,会导致程序运行的深度下降。
所以我们需要一个垃圾回收机制,对垃圾进行回收。
当一个对象没有任何的变量和属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是垃圾,必须对其进行清除。
JS中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作。我们需要做的只是将不再使用的对象设置为null即可。
学习的是B站尚硅谷的视频课程: