原型链
原型链类似关系链,几乎所有的js对象都会有通过原型链prototype继承过来的方法或者属性,
在java和c#中也存在一个默认继承的对象。js通过原型链给父类增加方法和属性,
子类就会产生对应的方法和属性,类似c#的扩展方法。改变某个对象的原型链可以改变其继承的父类。
- 当存在创建一个
Object.prototype.test=function(){}的时候,几乎所有的js对象都会存在一个test的方法。- 当存在创建一个
Number.prototype.test=function(){}的时候,几乎所有的js数字对象都会存在一个test的方法。- 当存在创建一个
String.prototype.test=function(){}的时候,几乎所有的js字符串对象都会存在一个test的方法。
其中__proto__不一定相等于prototype,
只有函数才有prototype和__proto__属性,对象只有__proto__。
每个对象都会在其内部初始化一个属性,就是__proto__,
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,
那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,
于是就这样一直找下去
关于继承的方式
-
通过实例化父类设置
prototype方法来继承对象的方法function p(){this.log=function(){}} function c(){} c.prototype=new p //会继承p的方法 Object.getPrototypeOf(new c);//输出 c.__proto__ 对象 -
通过实例化父类设置
prototype方法来继承对象的prototype方法function p(){} p.prototype.log=function(){} function c(){} c.prototype=new p //会继承p的方法 Object.getPrototypeOf(new c);//输出 c.__proto__ 对象 -
通过父类的
prototype设置prototype方法来继承对象的prototype方法function p(){this.logp=function(){}} p.prototype.log=function(){} function c(){} c.prototype=p.prototype //会继承p的prototype里面方法,不会继承logp c.prototype.test=function(){} Object.getPrototypeOf(new c);//输出 c.__proto__ 对象 -
通过实例化父类设置子类实例化的
__proto__方法来继承对象的方法function p(){this.logp=function(){}} p.prototype.log=function(){} function c(){} var obj=new c; obj.__proto__=new p; //会继承p的prototype里面方法以及logp方法 Object.getPrototypeOf(obj);//输出 c.__proto__ 对象 -
通过改变在改变父类
this的作用域的方式来执行父类方法继承父类的方法function p(){this.logp=function(){}} p.prototype.log=function(){} function c(){p.call(this)} var obj=new c; //只会继承logp方法
原型链相关的方法
hasOwnProperty
Array.prototype.log=function(){}
Array.prototype.hasOwnProperty('log') //true
for(key in []){console.log(key)} //log
如果没有判断就会导致遍历出扩展的方法
defineProperty
Object.defineProperty(object, propertyname, descriptor)
参数
object: 定义的对象
propertyname:参数名称
descriptor:定义的描述信息
descriptor
| 参数的键 | 描述 | 默认值 |
|---|---|---|
| configurable | 属性能否被删除或者重新定义 | false |
| enumerable | 遍历对象的时候属性是否可见 | false |
| value | 属性值,当设置后不能设置get和set
|
undefind |
| writable | 属性能否改变 | |
| get | 当获取属性的时候触发 | undefind |
| set | 当设置属性的时候触发 | undefind |
资料说writable默认值为false,但是当不设置这个参数的时候,value是可以改变的,持怀疑态度,求解
var user={};
Object.defineProperty(user, 'name', {
get:()=>{
console.log(`get value:${this.name}`)
return this.name;
},
set:value=>{
console.log(`set value:${value}`)
this.name=value;
}
});
注:下面设置会抛出异常
var user={};
Object.defineProperty(user, 'name', {
value:'johe',
get:()=>{
console.log(`get value:${this.name}`)
return this.name;
},
set:value=>{
console.log(`set value:${value}`)
this.name=value;
}
});
//Uncaught TypeError: Invalid property descriptor.
//Cannot both specify accessors and a value or writable attribute, #<Object>
defineProperties
Object.defineProperties(object, props)
参数
object: 定义的对象
props: 添加的属性, key和 value 分别Object.defineProperty 中的第二和第三个参数。
getPrototypeOf
Object.getPrototypeOf("test") //String {length: 0, [[PrimitiveValue]]: ""}
返回当前对象的原型链对象
__proto__与prototype的区别
-
__proto__与prototype相等的时候function c(){} c==c.prototype.constructor //true c==(new c).constructor //true (new c).__proto__===c.prototype //true
(new c).__proto__与c.prototype,(new c).constructor.prototype都是恒等的。
一旦prototype被赋予属性和方法,那么函数创建的实例会继承prototype上的属性和方法
-
__proto__与prototype存在不相等的时候function c(){} c.prototype={ log:function(){} } c==c.prototype.constructor //false c==(new c).constructor //false (new c).__proto__===c.prototype //true (new c).constructor===Object //true;
重写了
c.prototype后,(new c).__proto__与c.prototype还是恒等的,
但是c.prototype.constructor指向了Object,而不是c,因为{}默认是Object









网友评论