目录
原型对象
由来: 构造函数声明时系统JS会自动分配原型对象
作用:
1. 保存公共点属性和方法以供实例化对象访问.实例化对象不用构造和保存就可以直接使用原型对象上的属性和方法.但是实例化对象不能修改和删除原型对象上的属性和方法.
2. 修改原型对象以实现继承.
3. 原型对象自身可以重构或者添加原型对象的方法.自身具有增删改查的功能.
4. 由原型对象产生的原型链,可以通过修改原型链达到继承的目的.
访问原型对象:
1. 实例化对象通过实例化对象.__proto__来访问原型对象
2. 构造函数通过构造函数.prototype来访问原型对
书写一个函数,来查看原型对象的一类列操作
function Fn(){
info ='22222';
function fa (){
console.log('33333');
}
}
//通过构造函数直接查看原型对象
console.log(Fn.prototype);
// 通过实例化对象查看原型对象
let p = new Fn;
//查看原型对象
console.log(p.__proto__);
上段代码两者方法所查看的原型对象结果如下:
(想什么呢,结果肯定一样啊,原型对象就一个,无论怎么查看,都是这一个啊.)
为原型对象添加属性和方法
在原型对象上添加的属性和方法通过__proto__供实例化对象使用,通过prototype供构造函数使用.
function Fn(){
info ='22222';
function fa (){
console.log('33333');
}
}
//为原型对象添加属性和方法
Fn.prototype.info = '为原型对象添加属性';
Fn.prototype.say = function(){
console.log('为原型对象添加方法');
}
console.log(Fn); //查看函数Fn
console.log(Fn.prototype);//查看原型对象
在原型对象上添加属性和方法后的函数Fn和原型对象
为构造函数添加属性和方法
构造函数添加的属性和方法属于静态方法,保存在原型对象的constructor上 .
function Fn(){
info ='22222';
function fa (){
console.log('33333');
}
}
Fn.info = '333333';
Fn.da = function(){
console.log('这个会添加到哪里呢?');
}
console.log(Fn);
console.log(Fn.prototype);
console.log(Fn.da);
上边代码段的结果是:
为实例化对象添加属性和方法
实例化对象对属性和方法的改变并不能影响原型对象的属性和方法
实例化对象添加的属性和方法只能保存在实例化对象上,在原型对象上查看不到
function Fn(){
info ='22222';
function fa (){
console.log('33333');
}
}
//创建Fn的实例化对象
let f = new Fn();
f.info = '陌上花开...';
f.ra = function(){
console.log('借助实例化对象添加方法');
}
console.log(f);
console.log(f.__proto__);
console.log(Fn);
console.log(Fn.prototype);
上段代码结果:
warning:实例化对象不能修改原型对象的属性和方法.
对比上边三段添加属性和方法可以发现,最初的构造函数Fn上自带info属性,然后我们又给Fn的原型对象添加了info属性,接着又给实例化对象f添加了属性info,发现这仨info互不影响.
function Fn(){
info ='我是Fn上的添加info...';
function fa (){
console.log('33333');
}
}
//创建Fn的实例化对象
let f = new Fn();
f.__proto__.info = '我是原型对象上添加的info...'
f.info = '我是实例化对象添加的info...';
console.log(f.info); //我是实例化对象添加的info...
console.log(Fn.info); //undefined,在函数外部不能调用查看函数内部的属性
console.log(Fn.prototype.info); //我是原型对象添加的info...
注意:
在构造函数Fn外部查看Fn的属性info结果返回undefined,是因为函数的作用域是局部作用域,在函数外部不能查看,调用和使用.
为class添加属性和方法
面向对象中的class中添加的属性保存在实例化对象上
添加的方法保存在原型对象上
添加的箭头函数方法保存在实例化对象上
//class不能用,分隔语句
class Word{
info = 'dadaaada';
say(){
console.log('lalallaalalal');
};
row= () =>{
console.log('这是箭头函数...');
}
}
// 面向对象的封装必须创建一个实例化对象来进行访问
let w = new Word;
console.log(w.info);
console.log(w.row);
console.log(w);
console.log(w.__proto__);
上边代码的输出结果为:
注意:
当箭头函数不在class中时,与其他函数一样,存在局部作用域.但是箭头函数没有原型对象.
原型链
(图源于老师)
(person为构造函数,zs为实例化对象)
JavaScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法.
绿色的线表示原型链,当zs实例调用一个属性或者方法时,现在自身找,然后一层一层的向上,直至找到null.没有则返回undefined。(原型链的访问原则)
修改构造函数的原型链,方便实现继承.
更改原型链(更改原型对象)实现继承
通过Fn的实例化对修改Fn1的原型对象
可以直接将Fn的实例化对象赋值给Fn1的实例化对象,进而继承Fn的原型对象
也可以直接通过Fn的实例化对象访问原型对象然后将原型对象赋值给Fn1
//为原型对象添加属性和方法
Fn.prototype.info = '为原型对象添加属性';
Fn.prototype.say = function(){
console.log('为原型对象添加方法');
}
//创建Fn的实例化对象
let f = new Fn();
function Fn1 (){
name = 'zs';
function ha(){
console.log(2222);
}
}
Fn1.prototype = f; //可以直接将Fn的实例化对象赋值给Fn1的实例化对象,进而继承Fn的原型对象
console.log(Fn1.prototype.__proto__);
Fn1.prototype = f.__proto__; //也可以直接通过Fn的实例化对象访问原型对象然后将原型对象赋值给Fn1
console.log(Fn1.prototype);
console.log(Fn1.prototype.info); //输出为--- 为原型对象添加属性
原型对象的原型对象
Fn.prototype.prototype这种写法是不正确的,Fn.prototype的结果是原型对象,原型对象也是对象,所以查看对象的原型对象要使用__proto__
原型对象的原型对象是Object
原型对象的原型对象的原型对象是null
console.log(Fn.prototype.prototype); //undefined
console.log(Fn.prototype.__proto__); //Object
console.log(Fn.prototype.__proto__.__proto__); //null
注意:
为构造函数添加的方法属于静态方法,只能通过构造函数名调用,由实例化对象添加的方法也只能通过实例化对象名调用.
重构
对原型对象上的方法进行改造,达到个性化设计,使方法精准.
小栗子:
对数组方法forEach进行重构,直接数组中的number数据
// 在原型对象上重构原型对象的方法(重构forEach,只返回number类型数据)
// cb为回调函数
let arr = [];
Array.prototype.forEach = function(cb){
for (let i = 0;i < this.length;i++){
if(typeof this[i] == 'number'){
cb(this[i])
}
}
}
let arr2 = [12, 45, 'zs', 'ls', true, [11], '78'];
arr2.forEach(v => console.log(v)); // 12 45
原型对象小tips(总结):
1. 数组所有的方法都放在原型对象上,可以在数组的原型对象上添加方法。也可以重构原型对象方法.
2. class也存在原型对象.
3. 原型对象保存公共的属性和方法供实例化对象使用,但实例化对象不能对原型对象的属性和方法进行添加和修改.
4. 构造函数添加的属性和方法在原型对象的constructor上.
5. class添加的属性在实例化对象上,方法保存在原型对象上
6. 更改原型链以实现继承
7. 原型对象的原型对象是Object,原型对象的原型对象的原型对象是null
8. 为构造函数添加的方法属于静态方法.
9.原型链访问原则