【二】构造函数和原型

ES6(ECMAScript 6.0)之前js没有引入类的概念

在ES6之前,对象不是基于类创建的,而是用一种称为构建函数的特殊函数来定义对象和它们的特征

ES6之前创建对象可以通过以下三种方式创建对象:

对象字面量:

var obj ={
    
}

new Object():

var obj=new Object()

自定义构造函数:

function Star(name,age){
    this.name=name;
    this.age=age;
    this.sing=function(){
        console.log("我会唱歌!")
    }
}
var star=new Star("张三",20)
console.log(star.name);
star.sing()   //我会唱歌!

构造函数是一种特殊的函数,主要用于初始化对象,他总是与new一起使用,我们把对象的一些公共的属性和方法抽取出来,然后封装到这个函数里面

new 在执行时会做四件事情:

  1. 在内存中创建一个新的对象

  2. 让this指向这个新的对象

  3. 执行构造函数中的代码,给这个新对象添加属性和方法

  4. 返回这个新的对象

成员即是构造函数包含的属性和函数,而成员又分为:实例成员和静态成员

实例成员

实例成员就是在构造函数内部通过this添加的成员如上面的name、age和sing,实例成员只能通过实例化对象进行访问

var star=new Star("张三",20)
//star.kk=1029  这也是实例成员
console.log(star.name);

静态成员

在构造函数本身上添加的成员

star.sex='男'
console.log(star.sex)  //男

静态成员只能通过构造函数进行访问

【二】构造函数和原型_第1张图片

 

我们希望所有对象使用同一个函数,这样就比较节省内存,而解决方法就是我们接下来要讲的原型对象prototype(构造函数通过原型分配的函数是所有对象所共享的)

JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有,下面我们看看打印的构造函数:

【二】构造函数和原型_第2张图片

 

我们可以把哪些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法

以上面代码为例:

Star.prototype.sing=function(){
    console.log("我会唱歌")
}
let star=new Star()
star.sing()

所以一般情况下,我们的公共属性定义到构造函数里面,公共的方法放在原型对象上

每一个对象都有一个属性proto指向我们构造函数的原型对象,但是我们不能通过proto对原型对象中的属性进行赋值

接下来我们来仔细探讨一下构造函数、实例和原型对象之间的关系

function Star(username,age){
      this.username=username;
      this.age=age
    }
    Star.prototype.sing=function(){
      console.log("我会唱歌");
    }
    let star=new Star()
    console.log(Star.prototype);   //输出构造函数上的原型对象
    console.log(star);     //输出对象

上述程序运行结果如下:

【二】构造函数和原型_第3张图片

 

对象原型([[Protootype]])和构造函数(prototype)原型对象里面都有一个属性constructor属性,constructor我们称为构造函数,因为它指回构造函数本身
constructor主要用于记录该对象引用与哪个构造函数,它可以让原型对象指向原来的构造函数
很多情况下,我们需要手动的利用constructor这个属性指向原来的构造函数
Star.prototype = {
    movie: function(){
        console.log("我会演电影');
        }
 }//prototype是对象,如果这样赋值就会覆盖原来的对象,这会使得原型上没有了构造函数
 console.log(Star.prototype)

原型对象上没有了构造函数具体影响取决于你在代码中的使用方式。以下是可能的影响:

  1. 丢失原型链:通过将 star.prototype 设置为新的对象字面量,你将丢失默认的原型链。默认情况下,原型链是由构造函数和其原型对象构成的。如果没有了默认的原型对象,那么对象实例将不再具有原型链上的属性和方法的继承能力。

  2. 构造属性丢失:由于新的原型对象没有 constructor 属性,所以对象实例将不再具有指向构造函数的 constructor 属性。当你通过检查对象的构造属性来确定其构造函数时,将无法准确地识别对象的类型。

  3. 对象实例继承变更:新创建的对象实例将继承新原型对象上的属性和方法。在你的示例中,新对象实例将继承 movie 方法。这意味着你可以在新对象上调用 movie() 方法,输出 "我会演电影"。

请注意,由于丢失了默认的原型对象和构造属性,这种设置可能会导致代码的可读性和可维护性下降。通常情况下,最好不要完全替换原型对象,而是通过扩展或修改原型对象来添加或覆盖属性和方法。

以下是一个示例,展示了将 star.prototype 设置为新对象字面量的影响:

function Star(name) {
  this.name = name;
}
​
// 将 star.prototype 设置为新对象字面量
Star.prototype = {
  movie: function() {
    console.log("我会演电影");
  }
};
​
var star1 = new Star("张三");
​
// 对象实例继承了新原型对象上的方法
star1.movie(); // 输出:我会演电影
​
// 丢失了默认的构造属性
console.log(star1.constructor === Star); // false
console.log(star1.constructor); // 输出:[Function: Object]

在上述示例中,star1 对象实例继承了新的原型对象上的 movie 方法,可以调用该方法。但它失去了默认的构造属性,constructor 不再指向 Star 构造函数,而是指向 Object 构造函数。

这时我们需要手动添加constructor指回原来的构造函数

【二】构造函数和原型_第4张图片

 【二】构造函数和原型_第5张图片

【二】构造函数和原型_第6张图片 通过原型对象扩展内置对象

【二】构造函数和原型_第7张图片

 

你可能感兴趣的:(JavaScript,javascript,原型模式,面向对象)