1、定义
在JavaScript中,无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个 prototype 属性(指向原型对象)。默认情况下,所有原型对象自动获得一个名为 constructor 的属性,指回与之关联的构造函数。
fn = function() {};
fn.prototype; // {constructor: ƒ}
fn.prototype.construct === fn; // true
2、创建对象的几种方式
1.使用 Object 构造函数或对象字面量
虽然使用 Object 构造函数或对象字面量可以方便地创建对象,但这些方式也有明显不足:创建具 有同样接口的多个对象需要重复编写很多代码。
2.工厂模式
工厂模式是一种众所周知的设计模式,广泛应用于软件工程领域,用于抽象创建特定对象的过程。
function createPerson(name, age, job) {
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
console.log(this.name);
};
return o;
}
let person1 = createPerson("张三", 29, "前端");
let person2 = createPerson("李四", 27, "后端");
这里,函数 createPerson()接收 3 个参数,根据这几个参数构建了一个包含 Person 信息的对象。 可以用不同的参数多次调用这个函数,每次都会返回包含 3 个属性和 1 个方法的对象。这种工厂模式虽然可以解决创建多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)。
3.构造函数模式
ECMAScript 中的构造函数是用于创建特定类型对象的。像 Object 和 Array 这样的原生构造函数,运行时可以直接在执行环境中使用。当然也可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法。
本质是利用 构造函数在 new 的过程中 调用prototype.constructor,修改this指针指向实例 将属性、方法挂载在实例上
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { console.log(this.name) }
}
let person1 = new Person("张三", 29, "前端");
let person2 = new Person("李四", 27, "后端");
构造函数的问题
构造函数虽然有用,但也不是没有问题。构造函数的主要问题在于,其定义的方法会在每个实例上 都创建一遍。因此对前面的例子而言,person1 和 person2 都有名为 sayName()的方法,但这两个方 法不是同一个 Function 实例。我们知道,ECMAScript 中的函数是对象,因此每次定义函数时,都会 初始化一个对象。
console.log(person1.sayName === person2.sayName); // false
4.原型模式
每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型,
function Person() {};
Person.prototype.contry = '中国'
Person.prototype.city = '北京';
let person1 = new Person();
let person2 = new Person();
实例与构造函数原型之间有直接的联系,但实例与构造函数之间没有
3、new 的过程做了什么
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.city = '北京';
const person1 = new Person('张三', 18);
要创建 Person 的实例,应使用 new 操作符。以这种方式调用构造函数会执行如下操作。
- 在内存中创建一个新对象。
- 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性 - 原型模式
- 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)
- 执行构造函数内部的代码(给新对象添加属性)- 构造函数模式
- 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象
需要注意的是第5点,如果构造函数内部存在非空对象,则会返回该对象;
function Person(name, age) {
this.name = name;
this.age = age;
return {
contry: '中国'
}
}
Person.prototype.city = '北京';
const person1 = new Person('张三', 18);
const person2 = new Person('李四', 18);