持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
前言
大家好呀,我是L同学。在上篇文章js基本类型中,我们学习了js中的基本类型等相关知识点。今天,在这篇文章中,我们将学习js中的构造函数、原型、constructor属性、构造函数、原型、实例对象三者的关系等相关知识点。
构造函数
构造函数,就是一个普通的函数,只不过我们专门用它来生成对象。构造函数提供模板,描述对象的基本结构。一个构造函数,可以生成多个对象,这些对象都有相同的结构。
function Cat(name, color) {
this.name = name;
this.color = color;
this.say = function () {
console.log('hello'+this.name,this.color);
};
}
var cat1 = new Cat('猫', '白色');
var cat2 = new Cat('猫', '黑色');
cat1.say();
cat2.say();
构造函数出现的问题:
对于上述例子,对于每个实例对象,name和say属性都是一模一样的内容。每次生成一个实例,都必须为重复的内容,多占用一些内存。如果实例对象很多,会造成极大的内存浪费。
那么,能不能将相同的内容,放到公共部分,节约计算机资源呢?
原型
每一个构造函数都有一个prototype属性,这个属性就是实例对象的原型对象。 原型也是一个对象,原型对象上的所有属性和方法,都会被子对象(派生对象)共享。通过构造函数生成实例对象时,会自动为实例对象分配原型对象。
注意: null没有自己的原型对象。
针对构造函数出现的问题,我们可以把所有对象实例需要共享的属性和方法直接定义在构造函数的prototype属性上,也就是实例对象的原型上。
function Cat(color) {
this.color = color;
}
Cat.prototype.name = "猫";
Cat.prototype.sayhello = function(){
console.log('hello'+this.name,this.color);
}
Cat.prototype.saycolor = function (){
console.log('hello'+this.color);
}
var cat1 = new Cat('白色');
var cat2 = new Cat('黑色');
cat1.sayhello();
cat2.saycolor();
这时所有实例对象的name属性、sayhello、saycolor方法,都在同一个内存地址的对象中,也就是构造函数的prototype属性上,所以提高了运行效率,节省了内存空间。
当我们了解了什么是原型后,我们再回过头来看使用new操作符创建一个对象时,内部会进行什么操作呢?
- 在内存中创建一个新对象(空对象)
- 将这个空对象的原型,指向构造函数的prototype属性
function Person() {
}
let p1 = new Person()
// 上面的操作相当于会进行如下的操作
p = {}
p.__proto__ = Person.prototype
- 构造函数内部的this,会指向新创建出来的新对象
- 执行函数的内部代码
- 如果构造函数没有返回非空对象,则返回创建出来的新对象
constructor属性
原型对象上面都会添加一个属性constructor,这个constructor指向当前的构造函数。
function Person() {
}
let p1 = new Person()
console.log(Person.prototype.constructor); // [Function: Person]
console.log(p1.__proto__.constructor); // [Function: Person]