Js 对象进阶

🍹 JavaScript对象进阶需理解原型和继承机制,使用高阶函数和ES6新特性实现高效和灵活的对象操作,提升开发效率。

1 创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<script>
// 创建多个对象
var person1 = {
name: "刘一",
age: 20,
sayName: function () {
console.log(this.name);
}
};

var person2 = {
name: "陈二",
age: 21,
sayName: function () {
console.log(this.name);
}
};

var person3 = {
name: "张三",
age: 22,
sayName: function () {
console.log(this.name);
}
};

console.log(person1);
console.log(person2);
console.log(person3);
</script>

2 工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
// 使用工厂模式创建对象
function createPerson(name, age) {
// 创建新对象
var obj = new Object();
// 设置对象属性
obj.name = name;
obj.age = age;
// 设置对象方法
obj.sayName = function() {
console.log(this.name);
}
// 返回新对象
return obj;
}

for(var i = 1; i < 10; i++) {
var person = createPerson("Person" + i, 7);
console.log(person);
}
</script>

3 构造函数

  • 构造函数
    • 普通函数直接调用,构造函数需使用new关键字调用。
    • 类似于工厂方法,但是将创建对象和返回对象隐藏了。
    • 使用同一构造函数创建的对象,称为一类对象,也将一个构造函数称为一个类(模拟类)。
    • 构造函数习惯首字母使用大写形式,根据函数调用方式的不同,this将指向不同的对象。
      • 以函数的形式调用时,this永远都是指window。
      • 以方法的形式调用时,this则是调用方法的那个对象。
      • 以构造函数的形式调用时,this是新创建的那个对象。
      • 使用call和apply调用时,this是传入的那个指定对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script>
// 使用构造函数创建对象
function Person(name, age) {
// 设置对象属性
this.name = name;
this.age = age;
// 设置对象方法
this.sayName = function() {
console.log(this.name);
}
}

var person1 = new Person("刘一", 20);
var person2 = new Person("陈二", 21);
var person3 = new Person("张三", 22);

console.log(person1);
console.log(person2);
console.log(person3);

// 使用instanceof运算符检查一个对象是否是一个类的实例,返回true或false
console.log(person1 instanceof Person);
console.log(person2 instanceof Person);
console.log(person3 instanceof Person);
</script>

4 原型对象

  • 原型对象
    • 创建的每个函数,解析器都会向函数中添加一个属性prototype。
    • 这个属性对应着一个对象,这个对象就是原型对象,即显式原型。
    • 当函数以构造函数形式调用时,所创建的对象中都会有一个隐含的属性。
    • 指向该构造函数的原型对象,可通过__proto__(隐式原型)访问该属性。
      • 访问对象一个属性或方法时,先在对象自身中寻找。
      • 找到返回,没有就沿着__proto__这条链向上查找。
      • 找到返回,若最终没找到,返回undefined,这就是原型链。
      • 原型链又称为隐式原型链,作用则是查找对象的属性或方法。
    • Object对象是所有对象的老祖,原型对象指向为null,即无原型对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<script>
// 使用构造函数创建对象
function Person(name, age) {
// 设置对象属性
this.name = name;
this.age = age;
}

// 在Person类的原型对象中添加方法
Person.prototype.sayName = function() {
console.log(this.name);
};

var person1 = new Person("刘一", 20);
var person2 = new Person("陈二", 21);
var person3 = new Person("张三", 22);

person1.sayName();
person2.sayName();
person3.sayName();
</script>

5 对象继承

  • 对象继承
    • JavaScript是通过一种叫原型(prototype)的方式来实现面向对象编程的。
    • 实现继承的好处是子对象可以使用父对象的属性和方法,从而简化代码。
    • 六种经典的对象继承方式
      • 原型链继承、构造函数继承。
      • 原型式继承、寄生组合继承。
      • 寄生式继承、组合方式继承。

5-1 原型链继承

  • 原型链继承
    • 子类型的原型为父类型的一个实例对象。
    • 缺点
      • 不能传递参数,继承单一,多个实例的引用类型属性指向相同。
      • 一个实例修改了原型属性,另一个实例的原型属性也会被修改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<script>
// 定义父类型的构造函数
function SupType() {
this.supProp = "父类型";
}

// 给父类型原型添加方法
SupType.prototype.showSupProp = function() {
console.log(this.supProp);
};

// 定义子类型的构造函数
function SubType() {
this.subProp = "子类型";
}

// 创建父类型的对象赋值给子类型的原型
SubType.prototype = new SupType();

// 将子类型原型的构造属性设置为子类型
SubType.prototype.constructor = SubType;

// 给子类型的原型添加方法
SubType.prototype.showSubProp = function() {
console.log(this.subProp)
};

// 调用父类型的方法来创建子类型的对象
var subType = new SubType();
subType.showSupProp();
subType.showSubProp();
</script>

5-2 构造函数继承

  • 构造函数继承
    • 通过使用call()apply()方法将父类构造函数引入子类函数。
    • 使用父类构造函数增强子类实例,等同于复制父类的实例给子类。
    • 缺点
      • 只能继承父类的实例属性和方法,不能继承原型的属性和方法。
      • 无法实现构造函数的复用,每个子类都有父类实例函数的副本。
      • 影响性能,代码会臃肿。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script>
// 定义父类型的构造函数
function SupType(name) {
this.name = name;
this.showSupName = function() {
console.log(this.name);
};
}

// 定义子类型的构造函数
function SubType(name, age) {
// 在子类型中调用call方法继承自SupType
SupType.call(this, name);
this.age = age;
}

// 给子类型原型添加方法
SubType.prototype.showSubName = function() {
console.log(this.name);
};

// 创建子类型对象然后调用
var subType = new SubType("刘一", 20);
subType.showSupName();
subType.showSubName();
console.log(subType.name);
console.log(subType.age);
</script>

5-3 组合方式继承

  • 组合方式继承
    • 原型链继承、构造函数继承的组合方式继承。
    • 缺点
      • 父类的实例属性和方法即存在于子类的实例中,又存在于子类的原型中,后者仅是内存占用。
      • 使用子类创建实例对象时,原型会存在两份相同的属性和方法,该方法是最常用的继承模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<script>
function Person(name, age) {
this.name = name;
this.age = age;
}

Person.prototype.setName = function(name) {
this.name = name;
};

function Student(name, age, price) {
// 为得到父类型的实例属性和方法
Person.call(this, name, age);
// 添加子类型私有的属性
this.price = price;
}

// 为得到父类型的原型属性和方法
Student.prototype = new Person();
// 修正constructor属性指向
Student.prototype.constructor = Student;
// 添加子类型私有的方法
Student.prototype.setPrice = function(price) {
this.price = price;
};

var s = new Student("刘一", 20, 8000);
console.log(s.name, s.age, s.price);
s.setName("陈二");
s.setPrice(9000);
console.log(s.name, s.age, s.price);
</script>

6 垃圾回收

  • 垃圾回收
    • 当一个对象没有任何变量或属性对其进行引用,此时将无法操作该对象。
    • 该对象即垃圾,过多占用大量内存空间,导致程序运行变慢,必须清理。
    • Js拥有自动的垃圾回收机制,将这些垃圾对象从内存中销毁,需将不再使用的对象设为null。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
// 使用构造函数创建对象
function Person(name, age) {
// 设置对象的属性
this.name = name;
this.age = age;
}

var person1 = new Person("刘一", 20);
var person2 = new Person("陈二", 21);
var person3 = new Person("张三", 22);

person1 = null;
person2 = null;
person3 = null;
</script>

7 对象判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script>
// 创建一个构造函数
function MyClass() {
}

// 向MyClass的原型中添加一个name属性
MyClass.prototype.name = "原型名字";

// 创建一个MyClass的实例
var mc = new MyClass();
mc.age = 20;

// 使用in检查对象中是否含有某个属性时,如果对象中没有但原型中有,也会返回true
console.log("age" in mc);
console.log("name" in mc);

// 使用对象的hasOwnProperty()检查对象自身中是否含该属性
// 使用该方法时,只有当对象自身中含有该属性时才会返回true
console.log(mc.hasOwnProperty("age"));
console.log(mc.hasOwnProperty("name"));

// hasOwnProperty方法是原型中的,在执行方法时通过原型链查找,该方法是Object的特有方法
// 检查当前对象
console.log(mc.hasOwnProperty("hasOwnProperty"));
// 检查当前对象的原型对象
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"));
// 检查当前对象原型对象的原型对象
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));
</script>

8 toString()

  • toString()
    • toString()函数用于将当前对象以字符串的形式返回。
    • 该方法属于Object对象,由于所有对象都继承了Object的对象实例。
    • 几乎所有实例对象都可使用该方法,所有主流浏览器均支持该函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<script>
// 使用构造函数创建对象
function Person(name, age) {
// 设置对象属性
this.name = name;
this.age = age;
}

// 创建对象的一个实例对象
var p = new Person("刘一", 20);
console.log(p.toString());

// 字符串
var str = "Hi~";
console.log(str.toString());

// 数字
var num = 314;
console.log(num.toString());

// 布尔
var bool = true;
console.log(bool.toString());

// Object
var obj = {name: "陈二", age: 21}
console.log(obj.toString());

// 数组
var array = ["Hi~", "a", "b", 1, 2, 3, true];
console.log(array.toString());

// 错误
var error = new Error("自定义错误信息");
console.log(error.toString());

// 函数
console.log(Function.toString());

// 日期
var date = new Date(2024, 8, 12, 10, 33, 33);
console.log(date.toString());
</script>

Js 对象进阶
https://stitch-top.github.io/2024/08/14/web/web01-javascript/javascript03-js-dui-xiang-jin-jie/
作者
Dr.626
发布于
2024年8月14日 23:30:30
许可协议