JavaScript学习笔记(三):对象和函数

目录

一、对象

1.1 对象简介

1.2 对象的分类

1.3 对象的基本操作

1.4 属性名与属性值

1.5 对象字面量

1.6 函数

1.6.1 简介

1.6.2 函数的参数

1.6.3 函数的返回值

1.6.4 立即执行函数

1.7 方法

1.8 作用域

1.8.1 全局作用域

1.8.2 函数作用域

1.9 this

1.10 使用工厂方法创建对象

1.11 构造函数

1.12 原型对象

1.13 垃圾回收


一、对象

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站尚硅谷的视频课程:

尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值