构造函数,原型对象prototype,对象原型__pro__,原型链,成员查找机制,原型对象this指向,构造函数继承属性,原型对象继承方法详解
<!-- 创建对象可以通过以下三个方法 -->
<!--
1.对象字面量
let obj1={}
2.new Oject()
let obj2=new Oject()
3.自定义函数
function 函数名(){}
4.构造函数
构造函数用于创建某一类对象,起首字母要大写,必须要有new
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,
它总与new一起使用。我们可以把对象中一些公共的属性和方法抽离出来,然后封装到这个函数里面
new在执行时会做四件事情
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(所以构造函数里面不需要return)
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log("我会唱歌")
}
}
//不同的对象
var ldh=new Star('刘德华',18);
var zxy=new Star('张学友',18);
console.log(Idh)
// 同个方法
Idh.sing() //调用方法
zxy.sing()
-->
<!-- 构造函数中的属性和方法我们称为成员,成员可以添加 -->
<script>
function Star(name,age){
this.name=name;
this.age=age;
this.sing=function(){
console.log("我会唱歌")
}
}
var ldh=new Star('刘德华',18);
//实例成员就是构造函数内部通过this添加的成员 name age sing就是成员
// 实例成员就是实例化的对象来访问
console.log(Idh.name);
Idh.sing()
console.log(Idh.name); //实例成员只能通过实例化的对象来访问
console.log(Star.name); //不可以通过构造函数来访问实例成员
//静态成员 在构造函数本身上添加的成员 sex就是静态成员
Star.sex="男 ";
//静态成员只能通过构造函数来访问
console.log(Star.sex);
console.log(Idh.sex); //不能通过对象来访问静态成员
</script>
//原型对象
es6之前是 面向对象之前是由构造函数实现的,缺点是把方法放在构造函数里面,当我们创建实例的时候,会单独再创建一个内存空间,存放函数
我们在创建构造函数的两个不同实例对象的时候,会开辟两个不同的内存空间,比较浪费空间
// 对象使用同一个函数,比较节省内存
// 构造函数通过原型分配的函数时所有对象所共享的
// 每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
// 我们可以把那些不变的方法,直接定义在prototype对象上,这样所有的对象的实例可以共享这些方法
// 原型是一个对象,我们也称为prototype为原型对象
// 原型的作用是共享方法
function Star(name,age){
this.name=name;
this.age=age;
// this.sing=function(){
// console.log("我会唱歌")
// }
}
//一般情况下,我们的公共属性定义到构造函数里面,公共的属性和方法放到原型对象身上
Star.prototype.sing=function(){
console.log('我会唱歌');
}
var ldh=new Star( '刘德华',18);
var zxy=new Star('张学友',18);
console.log(ldh)
console.log(zxy);
// Idh.sing()
// zxy.sing()
//console.log(Idh.sing===zxy.sing); //false 比较是地址
//共享方法后:console.log(Idh.sing===zxy.sing) //true
// 对象原型_proto_
// 对象都会有一个属性_proto_指向构造函数的prototype原型对象
// 之所以对象可以使用构造函数prototype的属性和方法,就是因为对象有_proto_原型的存在
// __proto__对象原型和原型对象prototype是等价的
function Star(name,age){
this.name=name;
this.age=age;
// this.sing=function(){
// console.log("我会唱歌")
// }
}
Star.prototype.sing=function(){
console.log('我会唱歌');
}
var ldh=new Star( '刘德华',18);
var zxy=new Star('张学友',18);
console.log(ldh); //对象身上系统自动添加一个__proto__指向我们的构造函数的原型对象prototype
console.log(Lidh.__proto__===Star.prototype); //true
// 方法的查找规则:首先先看ldh对象身上是否有sing方法,如果有就执行这个对象
// 如果没有sing这个方法,因为有__proto__的存在,就去构造函数原型对象prototype身上去查找sing这个方法
成员的查找机制
function Star(name,age){
this.name=name;
this.age=age;
// this.sing=function(){
// console.log("我会唱歌")
// }
}
Star.prototype.sing=function(){
console.log('我会唱歌');
}
Star.prototype.sex='女'
// Object.prototype.sex='男'
ldh.sex='男' //如果实例对象也有,原型对象上也有,就用实例对象上的(就近原则)
var ldh=new Star( '刘德华',18);
console.log(ldh.sex);
原型对象this的指向
function Star(name,age){
this.name=name;
this.age=age;
// this.sing=function(){
// console.log("我会唱歌")
// }
}
var that;
Star.prototype.sing=function(){
console.log('我会唱歌');
that=this;
}
var ldh=new Star( '刘德华',18);
//在构造函数中,里面this指向的是对象实例ldh
ldh.sing()
console.log(that===ldh); //true
// 2.原型对象函数里面的this指向的是实例对象ldh
//原型对象的应用,扩展内置对象方法
console.log(Array.prototype);
Array.prototype.sum=function(){
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i]
}
return sum;
}
// Array.prototype={
// sum:function(){
// var sum=0;
// for(var i=0;i<this.length;i++){
// sum+=this[i]
// }
// return sum;
// }
// }
var arr=[1,2,3];
console.log(arr.sum()); // 6 arry是实例对象它调用了原型对象的sum方法
//借用父构造函数继承属性
// 1.父构造函数
function Father(name,age){
// this指向父构造函数的对象实例
this.name=name
this.age=age
}
// 2.子构造函数
function Son(name,age,sex){
// this指向子构造函数的对象实例
Father.call(this,name,age) //首先调用父构造函数,把夫构造函数的this改成子构造函数的this
this.sex=sex
}
var son=new Son('刘德华',18,'男');
console.log(son); //刘德华 18 男
原型对象继承方法
function Father(name,age){
// this指向父构造函数的对象实例
this.name=name
this.age=age
}
// 父构造函数专门的方法
Father.prototype.money=function(){
console.log(10000);
}
// 2.子构造函数
function Son(name,age,sex){
// this指向子构造函数的对象实例
Father.call(this,name,age) //首先调用父构造函数,把父构造函数的this改成子构造函数的this
this.sex=sex
}
// 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会发生改变
// Son.prototype=Father.prototype;
最终方法
Son.prototype=new.Father();//子的原型对象等于父的实例
//Son 继承了父的构造方法的同时,它自已的constructor也发生了改变, 所以如果利用对象的形式修改了原型对象,别忘了利用constructo指回原来的构造函数
Son.prototype.constructor=Son;
// 这个是子构造函数专门的方法
Son.prototype.exam=function(){
console.log('孩子要考试');
}
var son=new Son('刘德华',18,'男');
console.log(son);