1. 什么是对象?
在 JavaScript 中,对象是一种包含属性和方法的数据结构。你可以把对象想象成一个存储键值对的容器。每个键(key)都有一个对应的值(value),这个值可以是数据或者函数。
let person = {
name: "Alice",
age: 25,
greet: function() {
console.log("Hello, my name is " + this.name);
}
};
// 访问对象的属性和方法
console.log(person.name); // 输出: Alice
console.log(person.age); // 输出: 25
person.greet(); // 输出: Hello, my name is Alice
2. 什么是原型?
在 JavaScript 中,每个对象都有一个原型(prototype)。原型是另一个对象,所有的对象可以通过原型继承属性和方法。比如,JavaScript 中的所有对象默认继承自 Object.prototype
,而 Object.prototype
本身也是一个对象。
示例:继承自 Object.prototype
的方法
let obj = {};
console.log(obj.toString()); // 输出: [object Object]
在这个例子中,obj
是一个空对象。虽然我们没有定义任何属性或方法,但它仍然能使用 toString()
方法,因为它继承自 Object.prototype
,其中定义了 toString()
。
3. 原型链
当你访问对象的属性时,JavaScript 会首先在对象本身查找。如果没找到,它会去该对象的原型中寻找。这种逐层查找的机制被称为原型链。
示例:通过原型链查找属性
let animal = {
species: "Dog"
};
let pet = Object.create(animal); // pet 继承自 animal
pet.name = "Buddy";
console.log(pet.name); // 输出: Buddy (在 pet 对象本身找到)
console.log(pet.species); // 输出: Dog (在 pet 的原型 animal 中找到)
在这里,pet
继承自 animal
,当访问 pet.species
时,JavaScript 没有在 pet
本身找到 species
属性,于是转而去它的原型 animal
中查找,成功找到。
4. 对象原型污染的例子
原型污染的代码示例:
let innocentObject = {};
// 模拟用户输入的对象,其中有 __proto__ 属性
let userInput = {
__proto__: {
hacked: "Yes, I am hacked!"
}
};
// 合并用户输入到 innocentObject 中
Object.assign(innocentObject, userInput);
console.log(innocentObject.hacked); // 输出: undefined
console.log({}.hacked); // 输出: "Yes, I am hacked!"
解释:
- 在代码中,
userInput
包含__proto__
属性,这个属性指向一个包含hacked
属性的对象。 - 使用
Object.assign()
方法将userInput
合并到innocentObject
中。 - 虽然
innocentObject
本身没有hacked
属性,但是由于__proto__
被修改,JavaScript 的原型链被污染,Object.prototype
上被注入了一个hacked
属性。 - 结果是:所有对象(包括空对象
{}
)都能访问到这个被注入的hacked
属性。