狠狠污染链,狠狠的继承类
原型与原型链
想要原型链污染,先要了解什么是原型与原型链
Javascript
中一切皆是对象,其中对象之间是存在共同和差异的,比如对象的最终原型是Object
是原型null
,函数对象有prototype
属性,但是实例对象没有。
原型的定义
JavaScript原型是一种
对象继承的机制
,它允许对象共享属性和方法
。每个对象(
除了null
)都有一个原型对象,它可以通过__proto__
属性或Object.getPrototypeOf()
方法来访问。每个函数对象(除了箭头函数)都有一个
prototype
属性,它指向该函数作为构造函数时创建的实例对象的原型。
原型就是一个对象,它可以给其他对象提供共用的属性和方法。比如,你有一个人类的原型,它有姓名、年龄、说话等属性和方法,那么你可以用这个原型来创建很多人的对象,他们都会继承这些属性和方法。
原型链的定义
js 是由对象组成的,对象与对象之间存在着继承关系
每个对象都有一个指向它的原型的内部链接,而这个原型对象又有他自己的原型,直到
null
为止整体看来就是多个对象层层继承,实例对象的原型链接形成了一条链,也就是 js 的原型链
原型之间也可以相互继承,比如你有一个学生类的原型,它
继承了人类的原型
,但是它还有自己的属性和方法,比如学号、学习等。那么你可以用这个学生类的原型来创建很多学生的对象,他们既会继承人类的属性和方法,也会继承学生类的属性和方法。这样就形成了一个原型链,它决定了对象之间的关系。
原型对象的定义
原型对象是JavaScript中的一种特殊的对象,它可以被附加到其他对象或函数上,从而实现对象之间的继承和共享。原型对象本身也是一个对象,它有自己的原型,形成一个原型链。原型链在遇到
null
为原型的对象时结束。您可以通过设置或修改一个对象或函数的prototype
属性来改变它的原型。
1
2
3
4
5
6 >// 创建一个空对象
var obj = {};
>// 设置obj的原型为另一个对象
obj.__proto__ = {name: "Alice", age: 20};
// 访问obj的name属性,实际上是访问它的原型的name属性
console.log(obj.name); // Alice可以直接在控制台中进行
在JavaScript中,声明一个函数A的同时,浏览器在内存中创建一个对象B,然后A函数默认有一个属性
prototype
指向了这个对象B,这个B就是函数A的原型对象也叫函数A的原型
。这个对象B默认会有个属性constructor
指向了这个函数A。如下图中,函数
Foo
的prototype
指向{constuctor:f}
,而{constuctor:f}
的属性constuctor
指向函数Foo
实例对象
我们可以通过构造函数A构建一个实例对象A,A默认会有一个属性
__proto__
指向了构造函数A的原型B。
原型对象和实例对象的关系
如下图中,foo
为Foo
函数的实例化对象,foo
的__proto__
刚好等于Foo
函数的原型,返回为true
原型链机制
概念可以看一下
每个构造函数都有一个原型,原型都包含一个指向构造函数的指针(
constructor
),而实例都包含一个指向原型的内部指针(
__proto__
)。假如我们将一个构造函数的
prototype
属性设置为另一个类型的实例,那么该构造函数的原型对象将会指向另一个类型的原型。于是,这个新的原型对象也将包含一个指向另一个构造函数的prototype
对象的内部指针(__proto__
)。如此层层递进,就形成了一个由实例和原型构成的原型链。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 function Animal(name) {
this.name = name;
}
Animal.prototype.sayHello = function() {
console.log('Hello, my name is ' + this.name);
};
function Dog(name) {
Animal.call(this,name);
}
// 将 Dog 的原型设置为 Animal 的实例
//Object.create 创建一个新的对象,这个对象的原型指向 Animal.prototype,从而实现继承。
//Dog.prototype = Animal.prototype;这样会出现什么问题?两者会进行共享原型对象(Dog.prototype),这样修改Dog.prototype也会修改Animal.prototype中的内容
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Woof! Woof!');
};
let dog = new Dog('aa');
dog.sayHello(); // Hello, my name is aa
dog.bark(); // Woof! Woof!
console.log(dog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
概念太绕了,解析一下图片
Person
作为构造函数,每一个构造函数都有一个原型对象Person.prototype
,而原型对象都包含一个指向构造函数的指针[constructor
]
而其中person
作为Person
构造函数的实例[let person = new Person();
],也包含一个指向原型对象的内部指针[__proto__
]
于是最后这个原型链就是
person -> Person.protype -> Object.prototype -> null
可以看到原型链的结尾就是null
过滤绕过
__proto__
constructor.prototype