1.字符串和数字的转换
字符串转数组
-
使用
split()
方法- 根据指定的分隔符将字符串分割成数组
-
const str = "Hello, World!"; const arr = str.split(", "); // ["Hello", "World!"]
-
使用扩展运算符 (
...
)- 将字符串转换为字符数组
-
const str = "Hello"; const arr = [...str]; // ["H", "e", "l", "l", "o"]
-
使用
Array.from()
方法- 创建一个数组实例,包含字符串中的每个字符
-
const str = "Hello"; const arr = Array.from(str); // ["H", "e", "l", "l", "o"]
-
使用
Object.prototype.slice.call()
- 通过将字符串视为类数组对象进行转换
-
const str = "Hello"; const arr = Array.prototype.slice.call(str); // ["H", "e", "l", "l", "o"]
字符串转数字
-
使用
Number()
函数- 将字符串转换为数字
-
const str = "123.45"; const num = Number(str); // 123.45
-
使用
parseInt()
- 将字符串解析为整数
-
const str = "123.45"; const num = parseInt(str); // 123
-
使用
parseFloat()
- 将字符串解析为浮点数
-
const str = "123.45"; const num = parseFloat(str); // 123.45
-
使用一元加号 (
+
)- 通过在字符串前加上
+
来快速转换为数字 -
const str = "123.45"; const num = +str; // 123.45
- 通过在字符串前加上
-
使用
Math.floor()
,Math.ceil()
,Math.round()
- 这些方法可以将字符串转换为数字,并根据需要进行取整
-
const str = "123.45"; const num = Math.floor(str); // 123
总结
- 字符串转数组:常用方法有
split()
、扩展运算符、Array.from()
等。 - 字符串转数字:常用方法有
Number()
、parseInt()
、parseFloat()
和一元加号等。
2.至少说出一种开源项目(如Node)中应用原型继承的案例
示例:HTTP 服务器
Node.js 的 http.Server
和 http.IncomingMessage
是通过原型继承实现的。以下是一个简单的例子:
const http = require('http');
// 创建一个新的 HTTP 服务器
const server = http.createServer((req, res) => {
// req 是 http.IncomingMessage 的实例
console.log(req instanceof http.IncomingMessage); // 输出: true
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
// 服务器监听请求
server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});
原型继承的实现
在这个例子中:
http.Server
通过原型链继承了EventEmitter
,这使得服务器实例能够使用事件处理。http.IncomingMessage
也使用原型继承,以便在请求中添加额外的功能,例如请求头、请求方法等。
Express.js
Express.js 是一个流行的 Node.js Web 应用框架,它利用原型继承来实现中间件和路由处理。
示例
在 Express 中,Router
是通过原型继承自 EventEmitter
的。它允许你定义中间件和路由处理器:
const express = require('express');
const app = express();
const router = express.Router();
router.get('/', (req, res) => {
res.send('Hello from Router');
});
app.use('/router', router);
app.listen(3000, () => {
console.log('Server running at http://localhost:3000/router');
});
2. Mongoose
Mongoose 是一个 MongoDB 的对象建模工具,它使用原型继承来定义模型和文档。
示例
在 Mongoose 中,模型是通过构造函数和原型继承来创建的。例如,定义一个模型并创建实例:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: String,
age: Number,
});
const User = mongoose.model('User', userSchema);
const userInstance = new User({ name: 'Alice', age: 30 });
console.log(userInstance instanceof User); // 输出: true
3. Socket.io
Socket.io 是一个用于实时通信的库,使用原型继承来实现客户端和服务器端的通信逻辑。
示例
在 Socket.io 中,Socket 实例可以通过原型继承获取事件处理功能:
const io = require('socket.io')(3000);
io.on('connection', (socket) => {
console.log('New client connected');
socket.on('message', (msg) => {
console.log('Message received: ', msg);
});
});
在这个例子中,socket
是 Socket
类的实例,通过原型继承获取了处理事件的能力。
3.IIFE
IIFE(Immediately Invoked Function Expression,立即调用函数表达式)是一种在 JavaScript 中创建局部作用域的方法。它允许你定义一个函数并立即执行它,从而避免变量污染全局作用域。
语法
IIFE 的基本语法如下:
(function() {
// 这里是局部作用域
console.log('IIFE executed!');
})();
或使用箭头函数:
(() => {
console.log('IIFE executed with arrow function!');
})();
特点
- 局部作用域:IIFE 内部的变量不会泄露到外部作用域中,避免全局命名冲突。
- 立即执行:定义后立即执行,适合初始化任务或封装代码。
用法示例
1. 创建私有变量
const result = (function() {
const privateVar = 'I am private';
return function() {
console.log(privateVar);
};
})();
result(); // 输出: I am private
// console.log(privateVar); // 会报错: privateVar is not defined
2. 模块模式
IIFE 常用于模块化编程,封装相关代码:
const MyModule = (function() {
let privateVar = 'I am private';
return {
getPrivateVar: function() {
return privateVar;
}
};
})();
console.log(MyModule.getPrivateVar()); // 输出: I am private
总结
IIFE 是一种有效的 JavaScript 编程模式,能够创建局部作用域,避免全局变量污染,并且在需要立即执行代码的场景中非常实用。随着 ES6 的模块化功能引入,IIFE 的使用逐渐减少,但在某些场合依然非常有用
4.eval()
在 JavaScript 中,eval()
函数可以将一个 JSON 格式的字符串转换为对象,但这种方法存在安全风险,不建议使用。
let jsonStr = '{"name":"John","age":30}';
let obj = eval('(' + jsonStr + ')');
console.log(obj.name); // John
console.log(obj.age); // 30
不推荐使用eval()
的原因主要有以下几点:
安全风险:
- 如果处理的字符串来自不可信的源,攻击者可能会注入恶意代码,执行后可能会导致严重的安全问题,如窃取用户数据、篡改页面内容等。
性能问题:
- 通常,
eval()
的执行速度比其他安全的解析方法要慢。
更好的替代方法是使用JSON.parse()
函数来将 JSON 格式的字符串转换为对象:
let jsonStr = '{"name":"John","age":30}';
let obj = JSON.parse(jsonStr);
console.log(obj.name); // John
console.log(obj.age); // 30
5.描述new一个对象的详细过程,手动实现一个new操作符
new
操作符的工作原理
- 创建新对象:创建一个空对象(
{}
)。 - 设置原型:将新对象的
__proto__
属性指向构造函数的prototype
。 - 执行构造函数:调用构造函数,并将新对象作为
this
上下文。 - 返回对象:如果构造函数返回的是一个对象,则返回该对象;否则返回新创建的对象。
手动实现 new
操作符
我们可以通过一个函数来模拟 new
操作符的行为:
function myNew(constructor, ...args) {
// 1. 创建一个新对象
const obj = {};
// 2. 设置原型
Object.setPrototypeOf(obj, constructor.prototype);
// 3. 执行构造函数,绑定 this 为新对象
const result = constructor.apply(obj, args);
// 4. 返回新对象
return (result && typeof result === 'object') ? result : obj;
}
function Person(name) {
this.name = name;
}
const alice = myNew(Person, 'Alice');
console.log(alice.name); // 输出: Alice
console.log(alice instanceof Person); // 输出: true
6.理解es6 class构造以及继承的底层实现原理
1. class
的构造
- 构造函数:在类中定义的构造函数(
constructor
)在创建实例时自动调用。构造函数可以接收参数并初始化对象的属性。class Person { constructor(name) { this.name = name; } } const alice = new Person('Alice'); console.log(alice.name); // 输出: Alice
2. 继承
- 继承:使用
extends
关键字可以实现类的继承,子类可以继承父类的属性和方法。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const dog = new Dog('Rex');
dog.speak(); // 输出: Rex barks.
3. 底层实现原理
在底层,ES6 class
实际上是基于原型链实现的,以下是其工作原理:
a. 类的声明和构造
当你声明一个类时,JavaScript 会创建一个构造函数,类名就是构造函数的名称。
console.log(Person === Person.prototype.constructor); // 输出: true
b. 原型链
使用 extends
关键字时,子类的原型会自动设置为父类的实例,确保继承关系。
console.log(Dog.prototype.__proto__ === Animal.prototype); // 输出: true
c. 调用父类构造函数
在子类的构造函数中,必须调用 super()
,这会调用父类的构造函数并初始化继承的属性。
class Dog extends Animal {
constructor(name) {
super(name); // 调用父类构造函数
}
}
7.insertBefore()
insertBefore()
是 JavaScript 中用于操作 DOM 的方法,属于 Node
接口。它用于在指定的子节点之前插入一个新的子节点。
parentNode.insertBefore(newNode, referenceNode);
- parentNode:要插入新节点的父节点。
- newNode:要插入的新节点。
- referenceNode:在其之前插入新节点的现有子节点。如果为
null
,则新节点将被添加到子节点列表的末尾。返回值
- 返回插入的新节点。