跳到主要内容

构造函数与包装类

构造函数实例化对象

function Car(color, brand) {
this.color = color;
this.brand = brand;
this.drive = function () {
console.log('I am running');
};
}

const car1 = new Car('red', 'Baoma');

console.log(car1.color);
console.log(car1.brand);
car1.drive();

实例化时 this 的指向

在未实例化构造函数之前,this 指向全局对象 window。实例化构造函数后,this 指向新创建的对象,而不再指向构造函数本身。

function Car(color, brand) {
this.color = color;
this.brand = brand;
}

const car1 = new Car('red', 'Benz');
const car2 = new Car('black', 'Mazda');

console.log(car1.color);
console.log(car2.color);

指向 window

在构造函数未使用 new 关键字调用时,this 仍然指向全局对象 window

function Person(name, age) {
this.name = name;
this.age = age;
}

Person('Alice', 30);
console.log(window.name); // Alice
console.log(window.age); // 30

构造函数的执行上下文

在实例化过程中,this 对象在构造函数执行时被创建。当创建 car1 实例时,构造函数 Car 被执行,this 被赋予新对象的属性。

function Car(color, brand) {
this.color = color;
this.brand = brand;
}

const car1 = new Car('red', 'Benz');
console.log(car1.color);

new 关键字的作用

使用 new 关键字创建实例时,以下步骤会自动执行:

  1. 创建一个新的空对象,并将其赋值给 this
  2. 执行构造函数,将属性和方法添加到新对象。
  3. 返回新对象。
function Car(color, brand) {
const vehicle = {};
vehicle.color = color;
vehicle.brand = brand;
return vehicle;
}

const car = new Car('red', 'Mazda');
console.log(car);

相当于:

function createCar() {
const obj = {
name: 'Tom',
color: 'blue',
};
return obj;
}

const obj1 = createCar();
console.log(obj1.name);

new 构造函数的过程

let Parent = function (name, age) {
this.name = name;
this.age = age;
};

const child = new Parent('John', 25);

原始值与引用值

原始值包括 NumberStringBooleanNullUndefined。引用值包括 Object(包括 Array)、FunctionDateRegExp

当构造函数返回引用值时,系统返回该对象。当返回原始值时,系统忽略返回值并返回新创建的对象。

function Car() {
this.color = 'red';
this.brand = 'Benz';
return 123;
}

const car = new Car();
console.log(car.color); // red

包装类

数字对象

数字对象允许设置属性和方法。

let number = 1;
const numObj = new Number(number);
numObj.length = 1;
numObj.increment = function () {
console.log(number++);
};
console.log(number);
console.log(numObj);

对象与数字的运算

对象与数字进行运算时,会返回原始值。

let a = 1;
const numObj = new Number(a);
numObj.length = 1;
numObj.increment = function () {
console.log(1);
};
const result = numObj + 1;
console.log(result); // 2

三种包装类

NumberStringBoolean 是三种基本的包装类。

const str = 'abc';
console.log(str);

const strObj = new String('abc');
strObj.name = 'example';
console.log(strObj);
const concatenatedStr = strObj + 'bcd';
console.log(concatenatedStr);

const testNumber1 = new Number(undefined);
console.log(testNumber1);

const testNumber2 = new Number(null);
console.log(testNumber2);

const testString = new String(undefined);
console.log(testString);

undefinednull 不支持设置属性和方法。

console.log(undefined.length); // undefined

包装类的问题

let a = 123;
a.length = 3;
new Number(123).length = 3;
console.log(a.length); // undefined

const str = 'abc';
console.log(str.length); // 3

系统认为原始值没有属性和方法。使用包装类创建对象后,添加的属性无法持久化。

const obj = {
name: 'string',
};

console.log(obj);
delete obj.name;
console.log(obj);

系统处理过程

系统判断 obj 是引用值,可以添加和删除属性。当删除属性后,属性不再存在。

字符串属性

const str = 'abc';
console.log(new String(str).length); // 3

数组截断方法

通过修改数组的 length 属性,可以截断数组。

let arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); // [1, 2, 3]

字符串的截取

字符串是原始值,无法直接修改其 length 属性。

let str = 'abcde';
str.length = 3;
console.log(str); // 'abcde'

练习

累加器

创建一个闭包,实现累加功能。

function createAccumulator() {
let count = 0;

function add() {
console.log(++count);
}

return add;
}

const add = createAccumulator();

add(); // 1
add(); // 2

学生管理

使用对象封装学生管理功能,优化循环性能。

function StudentManager() {
const students = [];

const operations = {
join: function (name) {
students.push(name);
console.log(students);
},
leave: function (name) {
const index = students.indexOf(name);
if (index !== -1) {
students.splice(index, 1);
}
console.log(students);
},
};

return operations;
}

const manager = StudentManager();
manager.join('张三');
manager.leave('张三');

判断输出

展示包装类对原始值的影响。

let name = 'HTML';
name += 10; // 'HTML10'
const type = typeof name; // 'string'

if (type.length === 6) {
type.text = 'string';
}

console.log(type.text); // undefined

使用包装类后,可以设置属性。

let name = 'HTML';
name += 10; // 'HTML10'
const typeObj = new String(typeof name); // String object

if (typeObj.length === 6) {
typeObj.text = 'string';
}

console.log(typeObj.text); // 'string'

闭包与 this

通过闭包保持对内部变量的访问。

function Test(a, b, c) {
let d = 1;
this.a = a;
this.b = b;
this.c = c;

function increment() {
d++;
console.log(d);
}

this.g = increment;
}

const test1 = new Test();
test1.g(); // 2
test1.g(); // 3

const test2 = new Test();
test2.g(); // 2

函数赋值

函数可以赋值给变量并调用。

function greet() {
console.log('Hello');
}

const sayHello = greet;
sayHello(); // 'Hello'

作用域链示例

展示变量作用域和函数重定义的影响。

let x = 1,
y = (z = 0);

function add(n) {
return n + 1;
}

y = add(x);

function add(n) {
return n + 3;
}

z = add(x);

console.log(x, y, z); // 1, 2, 4

输出 12345

区分函数调用与表达式执行。

function foo1(x) {
console.log(arguments);
return x;
}

foo1(1, 2, 3, 4, 5);
// 输出: [1, 2, 3, 4, 5] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }

function foo2(x) {
console.log(arguments);
return x;
}

1, 2, 3, 4, 5;
// 语法错误:函数声明后不能直接跟执行符号

(function foo3(x) {
console.log(arguments);
return x;
})(1, 2, 3, 4, 5);
// 输出: [1, 2, 3, 4, 5] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }

映射关系

展示参数与 arguments 对象的对应关系。

function mapArguments(x, y, a) {
a = 10;
console.log(arguments[2]);
}

mapArguments(1, 2, 3); // 10

完善表格

如果文档中包含表格,确保表格内容完整且格式正确。以下是一个示例表格的完善:

| 数据类型  | 描述                     | 示例                               |
| --------- | ------------------------ | ---------------------------------- |
| Number | 数值类型 | `const num = 42;` |
| String | 字符串类型 | `const str = 'Hello';` |
| Boolean | 布尔类型 | `const flag = true;` |
| Object | 引用类型,包括数组、函数 | `const obj = {}`;`const arr = [];` |
| Null | 空值 | `const empty = null;` |
| Undefined | 未定义 | `let x;` |

最佳实践

在使用构造函数时,应尽量避免在构造函数内定义方法,而是将方法添加到原型链上,以节省内存并提高性能。

function Car(color, brand) {
this.color = color;
this.brand = brand;
}

Car.prototype.drive = function () {
console.log('I am driving');
};

const car1 = new Car('red', 'Benz');
car1.drive();

使用 class 语法可以使代码更加简洁和易读。

class Car {
constructor(color, brand) {
this.color = color;
this.brand = brand;
}

drive() {
console.log('I am driving');
}
}

const car1 = new Car('red', 'Benz');
car1.drive();

实战案例

创建一个简单的用户管理系统

class UserManager {
constructor() {
this.users = [];
}

addUser(name) {
this.users.push(name);
console.log(`${name} has been added.`);
}

removeUser(name) {
const index = this.users.indexOf(name);
if (index !== -1) {
this.users.splice(index, 1);
console.log(`${name} has been removed.`);
} else {
console.log(`${name} not found.`);
}
}

listUsers() {
console.log('Current Users:', this.users);
}
}

const manager = new UserManager();
manager.addUser('Alice');
manager.addUser('Bob');
manager.listUsers();
manager.removeUser('Alice');
manager.listUsers();

该案例展示了如何使用类来管理用户,包含添加、移除和列出用户的功能。