(141条消息) js原型链污染(超详细)_l_abour的博客-优快云博客_javascript原型链污染
原型的概念,作用,继承机制,重新,原型污染
1.什么是原型
JavaScript是一种简易的脚本语言,其是由对象构成。每一个JavaScript对象(除null外)都和另一个对象相关联,“另一个”对象就是原型。也就是说,任何一个对象都有原型这个属性。
- 隐式原型(__proto__):此属性继承自Object对象,在脚本中没有标准的方式访问
[[prototype]]
,但Firefox、Safari和Chrome在每个对象上都支持一个属性_proto_
。隐式原型的作用是用来构成原型链,实现基于原型的继承 - 显示原型(prototype):每一个函数在创建之后,便会拥有一个prototype属性,这个属性指向函数的原型对象。显示原型的作用是用来实现基于原型的继承与属性的共享
2.原型的作用,解决了什么问题
- 构造函数的缺陷
构造函数是通过new运算符创建并初始化一个新的对象,关键字new后跟随一个函数调用,这个函数称为构造函数,构造函数用来初始化一个新创建的对象。
现在有一个Person的构造函数,表示人对象的原型补充:new的过程
function Person(name) { this.name = name this.address = "上海" // 设置一个实例对象的共有属性address } //生成人对象实例 var person1 = new Person('Tom') var person2 = new Person('Jack')
这两个对象的address属性是独立的,修改其中一个,不会影响到另一个
person1.address = "北京" console.log(person2.address) // 上海,不受person1的影响
每一个实例对象都有自己的属性和方法的副本,由于无法做到数据共享,导致资源的浪费。所以,为了解决数据无法共享的问题,引入了prototype属性,prototype属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法,也就是说prototype是通过调用构造函数而创建的那个对象实例的原型对象。因此我们可以将实例对象需要共享的属性和方法都放在这个对象中。
现在对上面的Person方法进行重写,假设我们需要address这个属性是共享的,但是name是独有的。function Person(name) { this.name = name } Person.prototype = { address: "上海" } //生成人对象实例 var person1 = new Person('Tom') var person2 = new Person('Jack') //修改共享的属性address Person.prototype.address = "北京" console.log(person1.prototype) // 北京 console.log(person2.prototype) // 北京
address属性放在了Person的prototype对象中,创建实例后,两个实例也将address属性放在了原型对象中,这两个实例对象共享这个属性,只要修改Person中的prototype对象,就会同时影响两个实例对象
JavaScript的原型是为了实现对象间的联系,解决构造函数无法数据共享而引入的一个属性。而原型链是一个实现对象间联系即继承的主要方法。
1。对应名称
prototype:原型
__proto__: 原型链:链接点
2。从属关系
prototype ==> 函数的一个属性:对象{},该属性是一个指针, 指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。 就是当我们创建一个函数的时候,系统就会自动分配一个 prototype属性,可以用来存储可以让所有实例共享的属性和方法
__proto__==>对象Object的一个对象,Object也是一个函数
对象的__proto__保存着该对象的构造函数的prototype
对应下面代码的: console.log(test.__proto__===Test.prototype);
function Test(){
this.a=1
// //let i = 0
// for(var i = 0; i < 6; i++){
// setTimeout(()=>{
// console.log('i',i)
// },0)
}
Test.prototype.b=3
// 这里的Object可以理解为Object对象的构造函数
Object.prototype.c=6
// new出来的是一个对象出来
let test=new Test()
// ===深刻理解下面的代码,test是一个对象,对象挂载__proto__对象,__proto__对象保存着该对象的构造函数的prototype
// 原型链:以一个对象为基准,以__proto__为链接的一条链条,一直到Object.prototype为止
// test{
// a:1,
// __proto__:Test.prototypy={
// b=2,
// __proto__:Object.prototype={//顶层
// c=6
// 不存在 __proto__:null
//
// }
// }
// }
// 原型继承:只有你构造了我才可以使用我,例如上面的test使用原型继承时只能使用a
// 原型链继承:
console.log('test',test)
console.log(test.a);
console.log(test.b);
console.log(test.c);
console.log(test.__proto__===Test.prototype);
console.log(Test.prototype.__proto__===Object.prototype);
console.log('Object',Object.prototype);
//2 函数和对象的特殊性 Function,Object
console.log('Test',Test.__proto__===Function.prototype);
// const Test= new Function(){}
// Function的proto指向自己的本身prototype,Function构造了自己本身
console.log(Function.prototype===Function.__proto__);
//Object本身就是一个函数,所以具有下面的属性
console.log(Function.prototype===Object.__proto__);
// 64和65行推出下面的结论=》
console.log(Object.__proto__===Function.__proto__);
// 3判断属性是否存在
// hasOwnProperty:(判断对象内部)是否在test的这个原型上,不在Object
// in:链条是否存在某个属性,包括Object
console.log(test.hasOwnProperty('a'));
console.log('a' in test);
// constructor与实例直接的关系和特性,构造函数可以更改
console.log(test.constructor===Test);
function test1(){
this.a=1111
}
test.constructor=test1
console.log('ttete',test);
test对象的原型链:
test{
a:1,
__proto__:Test.prototypy={
b=2,
__proto__:Object.prototype={//顶层
c=6
不存在 __proto__:null
}
}
}
原型链的特点:
function Person(){} Person.prototype.name = 'tt'; Person.prototype.age = 18; Person.prototype.sayHi = function() { alert('Hi'); } var person1 = new Person(); var person2 = new Person(); person1.name = 'oo'; person1.name // oo person1.age // 18 perosn1.sayHi() // Hi person2.age // 18 person2.sayHi() // Hi
从这段代码我们不难看出:
- 实例可以共享原型上面的属性和方法
- 实例自身的属性会屏蔽原型上面的同名属性,实例上面没有的属性会去原型上面找
原型也是对象,那么就可以重写这个原型对象
function Person() {} Person.prototype = { name: 'tt', age: 18, sayHi() { console.log('Hi'); } } var p = new Person()
只是当我们在重写原型链的时候需要注意以下的问题:
function Person(){} var p = new Person(); Person.prototype = { name: 'tt', age: 18 } Person.prototype.constructor === Person // false p.name // undefined