JavaScript (四) ——构造函数原型 , 原型链 和继承

原型

  1. 所有引用类型都有一个_proto_属性, 属性值是对象
  2. 所有函数都有一个prototype属性 , 属性值是一个对象
  3. 所有引用类型的_proto_属性 , 都指向其构造函数的prototype
  • _proto_是给浏览器使用的 , prototype是给程序员使用的
  • 原型的作用 : 数据共享, 节省空间
    在构造函数中定义的属性和方法,
    当实例化对象的时候,实例对象中的属性和方法都是在自己的空间中存在的,
    如果是多个对象, 这些属性和方法都会在单独的空间中存在,浪费内存空间,
    所以,为了数据共享,把想要节省空间的属性或者方法写在原型对象中,达到了数据共享,节省了内存空间。

constructor 构造函数

对象原型( proto)和构造函数(prototype)原型对象里面都有一个属性constructor
属性constructor我们称为构造函数,它指回构造函数本身
constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。

一般情况下,对象的方法都在构造函数的原型对象中设置。
如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,
但是这样就会覆盖构造函数原型对象原来的内容,
这样修改后的原型对象constructor 就不再指向当前构造函数了。
此时,我们可以在修改后的原型对象中,添加一个 constructor指向原来的构造函数

如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数如:

function Star(uname, age) {
     this.uname = uname;
     this.age = age;
 }
 // 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
 Star.prototype = {
 // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用
constructor指回原来的构造函数
   constructor: Star, // 手动设置指回原来的构造函数
   sing: function() {
     console.log('我会唱歌');
   },
   movie: function() {
     console.log('我会演电影');
   }
}
var zxy = new Star('张学友', 19);
console.log(zxy)

原型链

当访问一个对象的属性时,
我们先去这个对象本身的属性去查找,
如果没有 就去这个对象的_proto_隐式属性查找, 其指向的是它构造函数的 prototype 属性
如果没有 再去这个构造函数的 __proto__ 查找 , 其指向这个构造函数的构造函数的 prototype
这就叫原型链

举例 :

function Parent(month){
    this.month = month;
}

var child = new Parent('Ann');

console.log(child.month); // Ann

console.log(child.father); // undefined

在这里插入图片描述
Object.prototype.__proto__ === null
一直往上层查找,直到到null还没有找到,则返回undefined

this指向

构造函数中的this和原型对象的this,都指向我们new出来的实例对象

继承

  1. JS没有像java的class那样的类
  2. 我们的构造函数 就类似java里的class
  3. 继承也是模拟继承
  4. 模拟继承是为了实现数据共享,节省内存空间。
  • 原型继承 子级.prototype = new 父级()
function Person(name, age, sex) { // 父级
	this.name = name;
	this.sex = sex;
	this.age = age;
}
Person.prototype.eat = function() {
	console.log("吃饭");
};
function Student(score) { //子级
	this.score = score;
}
Student.prototype = new Person("张三", 18, "男");//改变子级的原型的指向即可让子级继承父级
Student.prototype.study = function() {
	console.log("studing");
};
var stu = new Student(99);

// 继承父级过来的属性和方法:
console.log(stu.name); // 张三
console.log(stu.age); // 18
console.log(stu.sex); // 男
stu.eat(); // 吃饭

// 子级自带的属性和方法:
console.log(stu.score); // 99
stu.study(); // studing

利用原型继承的弊端 :
我们改变原型指向的同时,直接初始化了属性,这样继承过来的属性的值都是一样的了。
这是个问题,如果我们想要改变继承过来的值,只能重新调用对象的属性进行重新赋值,这又导致我们上边的初始化失去了意义。
所以我们有call 继承

  • 利用call()继承

call() 用来调用函数

call() 可以修改this的指向,使用call()的时候 第一个参数是修改后的this指向,后面的参数 使用逗号隔开连接

 function fn(x, y) {
     console.log(this);
     console.log(x + y);
}
  var o = {
   name: 'andy'  
  };
  fn.call(o, 1, 2);//调用了函数此时的this指向了对象o,

在这里插入图片描述

  • 组合继承

既用原型继承 又用call()继承

这样 既可以保证每个实例都有它自己的属性,又能做到对一些属性和方法的复用。

//父级
function Person(name) {
	this.name = name;
}
Person.prototype.sayHi = function() {
	console.log("你好");
};
//子级
function Student(name, score) {
	Person.call(this, name); //借用call()函数:解决属性值重复的问题
	this.score = score;
}
//改变原型指向 : 原型继承解决原型方法不能被继承问题
Student.prototype = new Person(); //不传值
Student.prototype.study = function() {
	console.log("studing");
};
var stu1 = new Student("张三", "100分");
console.log(stu1.name, stu1.score);
stu.sayHi();
stu.study();
var stu2 = new Student("李四", "99分");
console.log(stu2.name, stu2.score);
stu2.sayHi();
stu2.study();
  • for in 拷贝继承

把一个对象中的属性或者方法直接复制到另一个对象中
新对象通过拷贝函数原型prototype对象中的属性和方法继承prototype对象的属性和方法

下面这个例子 :

Person中有原型prototype,prototype就是一个对象,那么里面,name,age,sex,height,play都是该对象中的属性或者方法

function Person() {}
Person.prototype.name = "张三";
Person.prototype.age = 18;
Person.prototype.sex = "男";
Person.prototype.height = 180;
Person.prototype.study = function() {
	console.log("studing");
};
var obj = {};
for (var k in Person.prototype) { //for in 拷贝prototype的属性和方法
	obj[k] = Person.prototype[k];
}
console.dir(obj);
obj.study();

参考原文
【原型和原型链】什么是原型和原型链
ES6基础2-- 构造函数和原型
JavaScript 进阶教程(3)—让你彻底搞懂原型链和继承

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值