原型链
原型链类似关系链,几乎所有的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
网友评论