构造函数与包装类
构造函数实例化对象
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
关键字创建实例时,以下步骤会自动执行:
- 创建一个新的空对象,并将其赋值给
this
。 - 执行构造函数,将属性和方法添加到新对象。
- 返回新对象。
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);
原始值与引用值
原始值包括 Number
、String
、Boolean
、Null
和 Undefined
。引用值包括 Object
(包括 Array
)、Function
、Date
和 RegExp
。
当构造函数返回引用值时,系统返回该对象。当返回原始值时,系统忽略返回值并返回新创建的对象。
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
三种包装类
Number
、String
和 Boolean
是三种基本的包装类。
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);
undefined
和 null
不支持设置属性和方法。
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();
该案例展示了如何使用类来管理用户,包含添加、移除和列出用户的功能。