JavaScript使用原型继承模型,这与许多其他语言使用的基于类的模型有很大区别。在本节中,我们将提供一个基本概述,以便您能够理解我们关于原型污染漏洞的学习材料。
在JavaScript中,什么是对象?
JavaScript对象本质上只是一组称为“属性”的键值对集合。例如,以下对象可以表示一个用户:
const user = {
username: "wiener",
userId: 01234,
isAdmin: false
}
您可以使用点表示法或括号表示法访问对象的属性来引用它们各自的键:
user.username // "wiener"
user['userId'] // 01234
除了数据,属性还可以包含可执行函数。在这种情况下,该函数被称为“方法”。
const user = {
username: "wiener",
userId: 01234,
exampleMethod: function(){
// do something
}
}
上面的示例是“对象字面量”,这意味着它使用花括号语法显式声明其属性及其初始值。但是,重要的是要了解JavaScript中几乎所有内容都是对象。在这些材料中,“对象”一词指所有实体,而不仅仅是对象字面量。
JavaScript中的原型是什么?
JavaScript中的每个对象都与另一个对象链接在一起,这被称为它的原型。默认情况下,JavaScript会自动为新对象分配其中一个内置原型。例如,字符串会自动分配内置的String.prototype。您可以在下面看到一些全局原型的更多示例:
let myObject = {};
Object.getPrototypeOf(myObject); // Object.prototype
let myString = "";
Object.getPrototypeOf(myString); // String.prototype
let myArray = [];
Object.getPrototypeOf(myArray); // Array.prototype
let myNumber = 1;
Object.getPrototypeOf(myNumber); // Number.prototype
对象自动继承其分配的原型的所有属性,除非它们已经拥有相同键的自己的属性。这使开发人员能够创建可以重用现有对象的属性和方法的新对象。
内置原型为使用基本数据类型提供有用的属性和方法。例如,String.prototype对象具有toLowerCase()方法。因此,所有字符串都自动具有用于将它们转换为小写的就绪方法。这使开发人员无需手动将此行为添加到每个新字符串中。
JavaScript中的对象继承是如何工作的?
每当您引用对象的属性时,JavaScript引擎首先尝试直接在对象本身上访问它。如果对象没有匹配的属性,则JavaScript引擎会在对象的原型上查找它。例如,给定以下对象,这使您可以引用myObject.propertyA:
您可以使用浏览器控制台来查看此行为。首先,创建一个完全空的对象:
let myObject = {};
接下来,键入myObject,后跟一个点。注意,控制台会提示您从属性和方法列表中进行选择:
尽管对象本身没有定义任何属性或方法,但它已经从内置的 Object.prototype 继承了一些属性和方法。
原型链
请注意,对象的原型只是另一个对象,它也应该有自己的原型,依此类推。由于 JavaScript 中的几乎所有东西在底层都是对象,因此这个链最终会回到顶层的 Object.prototype,其原型只是 null。
关键是,对象不仅继承其直接原型的属性,还继承其原型链中上层所有对象的属性。在上面的示例中,这意味着username对象可以访问String.prototype和Object.prototype的属性和方法。
使用__proto__访问对象的原型
每个对象都有一个特殊的属性,您可以使用它来访问其原型。尽管这个属性没有正式标准化的名称,但__proto__是大多数浏览器使用的事实标准。如果您熟悉面向对象的语言,这个属性既可以作为对象原型的getter,也可以作为setter。这意味着您可以使用它来读取原型及其属性,并在必要时重新分配它们。
与任何属性一样,您可以使用方括号或点表示法访问__proto__:
username.__proto__
username['__proto__']
你甚至可以链接引用__proto__,以此沿着原型链向上遍历:
username.__proto__ // String.prototype
username.__proto__.__proto__ // Object.prototype
username.__proto__.__proto__.__proto__ // null
修改原型
尽管通常被认为是不好的做法,但是可以像修改其他对象一样修改JavaScript的内置原型。这意味着开发人员可以定制或覆盖内置方法的行为,甚至可以添加新的方法来执行有用的操作。
例如,现代JavaScript为字符串提供了trim()方法,它使您可以轻松地删除任何前导或尾随的空白。在引入这个内置方法之前,开发人员有时会通过像这样在String.prototype对象上添加自定义实现来实现这种行为:
String.prototype.removeWhitespace = function(){
// 删除前导和尾随空白
}
由于原型继承的关系,所有字符串都可以访问到这个方法:
let searchTerm = " example ";
searchTerm.removeWhitespace(); // "example"
刚更新了网安就业的视频,后续b站要多多更新了:
原文始发于微信公众号(黑伞安全):JavaScript 原型和继承
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论