一、构造函数
在JavaScript当中,函数的调用方式有很多种,其中我们可以通过new来调用函数,这种称为构造函数。我们可以通过构造函数来生成同样的结构但不同的值,直接上代码。
function Person(name,age) {
this.name = name;
this.age = age;
this.sayName = function (){
console.log(this.name);
}
}
const person1 = new Person("小明",20) // {name: "小明",age: 20,sayName: fn}
person1.name // "小明"
person1.age // 20
person1.sayname() // "小明"
const person2 = new Person("小红",30) // {name: "小明",age: 30,sayName: fn}
person2.name // "小红"
person2.age // 30
person2.sayname() // "小红"
在上面代码中,我们通过new来调用Person构造函数,我们可以看到person1是一个对象,为什么会是一个对象呢?为什么要在Person当中使用this呢?因为我们使用new操作符的时候,代码做了这些事:
- 在内存当中声明一个对象。
- 将构造函数的原型赋值给对象的原型。
- 将this指向这个对象。
- 执行构造函数当中的代码。
- 如果构造函数返回一个非空对象,则直接返回该对象,否则返回刚创建的新对象。
原型对象
在对象当中都有一个属性 prototype 这个就是原型对象,构造函数通过.prototype来访问原型,实例或字面量对象通过.__proto__来访问原型,函数也是一个对象。原型对象当中的属性和方法都是共享的。在上面的例子当中,我们通过构造函数创建了两个对象,都有sayName方法,这就很没有必要,因为这两个方法是相同的,所以我们可以通过将sayName方法添加到原型当中来完成实例之间的共享。
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const person1 = new Person("小明",20) // {name: "小明",age: 20,sayName: fn}
person1.name // "小明"
person1.age // 20
person1.sayName() // "小明"
const person2 = new Person("小红",30) // {name: "小红",age: 30,sayName: fn}
person2.name // "小红"
person2.age // 30
person2.sayName() // "小红"
我们还可以通过原型当中的constructor属性来确定这个实例是由哪个构造函数创建的。
Person.prototype.constructor // Person() 表明这个实例是由Person构造函数创建的
原型链
先来看一段代码
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const person1 = new Person("小明",20) // {name: "小明",age: 20,sayName: fn}
person1.sayName() // "小明"
在上面我调用了sayName方法,并成功打印了小明,但sayName不是在原型对象上吗,为什么可以调用呢?在上面我说原型对象当中的属性和方法是共享的,但是为什么是共享的?因为js有原型链查找机制。访问一个属性的过程
- 先在自身找,如果可以找到,则停止。
- 找不到则向原型上去找。
- 再找不到则向原型的原型去找。
- 循环往复,如果返回null,则代表没有这个属性。
以上就是本人对于原型、原型链的理解。