隐式原型
每个对象都有一个属性__proto__(也可以称为隐式原型),它指向该对象的原型。当我们访问一个对象的属性时,如果该对象本身没有该属性,那么就会到它的原型对象上查找,如果还是没有,则会继续沿着原型链往上查找,直至找到Object.prototype为止。
对象的原型可以通过以下方式访问:
- Object.getPrototypeOf(obj)
- obj.proto
判断一个对象是否具有某个属性:
- 使用
in运算符。 - Object.hasOwnProperty()
- 使用
Object.getOwnPropertyNames()方法或Object.keys()方法
原型对象
在 JavaScript 中,每个函数都有一个 prototype 属性,它是一个对象,用于存储该函数的实例对象所共享的属性和方法。这个 prototype 对象可以看作是构造函数的模板,通过它可以实现对实例对象的继承。
改变原型对象的方法:
- 使用
Object.create()方法 - 直接改变原型对象
构造函数
构造函数是一种特殊类型的函数,用于创建新对象和初始化该对象的属性和方法。在 JavaScript 中,我们可以通过定义一个构造函数来实现对象的创建和初始化。
构造函数的命名约定通常使用大写字母开头,以便与普通函数进行区分。例如:
function Person(name, age) {
this.name = name;
this.age = age;
}
要调用一个构造函数,需要使用 new 关键字。
Object.create()方法和new关键字
Object.create() 方法和 new 关键字都可以用于创建新对象,但它们之间存在一些区别。
Object.create()方法创建的新对象的原型是通过参数传递进去的,而new关键字创建的新对象的原型是构造函数的prototype属性。因此,使用Object.create()方法可以更加灵活地指定对象的原型。Object.create()方法只能用于创建普通对象,而无法用于创建函数对象、数组对象等其他类型的对象。相比之下,new关键字可以用于创建各种类型的对象,包括普通对象、函数对象、数组对象等。- 在使用
new关键字创建新对象时,构造函数会自动返回一个新对象。而在使用Object.create()方法创建新对象时,返回的是一个空对象,需要手动添加属性和方法。
举个例子:
function Person(name, age) {
this.name = name;
this.age = age;
}
// 使用 new 关键字创建对象
const person1 = new Person('Tom', 18);
// 使用 Object.create() 创建对象
const person2 = Object.create(Person.prototype);
person2.name = 'Jerry';
person2.age = 20;
new运算符执行过程
当我们使用new运算符来创建一个对象时,会经历以下步骤:
- 创建一个空对象。
- 将这个空对象的__proto__属性指向构造函数的原型对象(也就是构造函数的prototype属性所指向的对象)。
- 执行构造函数,并将this指向这个空对象。
- 如果构造函数返回一个对象,则返回这个对象,否则返回第一步创建的空对象。
可以通过以下代码来模拟一下new运算符的执行过程:
function myNew(constructor, ...args) {
const obj = Object.create(constructor.prototype);
// 上面隐含了 obj.__proto__ = constructor.prototype
const result = constructor.apply(obj, args);
return result instanceof Object ? result : obj;
}
原型链实现继承
函数也有原型属性。我们可以通过给函数的原型属性添加方法来使得该函数创建的所有实例对象都具有这个方法。利用这个原理,我们可以使用原型链实现继承。
下面是一个简单的例子,来说明利用原型链实现继承的方式:
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function() {
console.log(`My name is ${this.name}.`);
}
function Dog(name, color) {
Animal.call(this, name);
this.color = color;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.sayColor = function() {
console.log(`My color is ${this.color}.`);
}
const dog1 = new Dog('Tom', 'white');
dog1.sayName(); // My name is Tom.
dog1.sayColor(); // My color is white.
说明下:
- 传参:创建实例对象时,通过显示绑定this的方式向构造函数(父级)传参。
- Object.create:创建一个新对象,使用现有的对象来作为新创建对象的原型。
- Dog.prototype.constructor指向Dog本身。这是因为在将原型对象重写时,constructor属性会丢失,我们需要手动设置回来。