JS中的原型和原型链
今天带大家了解一下前端js中一个比较基础但也很关键的内容原型和原型链
一、原型:对象背后的“共享工具箱”
1. 原型到底是什么?
在JavaScript中,每个对象(除了null)在创建时,都会默认关联另一个对象,这个被关联的对象就是“原型”。你可以把它理解成一个“共享工具箱”——里面存放着一些属性和方法,供关联的对象直接使用,不用每个对象都单独定义一遍。
比如我们创建一个对象let obj = { name: 'test' },虽然没给它写toString()方法,但调用obj.toString()时却能正常执行。这是因为obj的原型里自带了这个方法,obj直接“借用”了过来。
2. 原型的3个关键角色:prototype、__proto__和constructor
要搞懂原型,必须分清这三个“符号”:
• prototype:只有函数才有这个属性,它指向一个对象(即“原型对象”)。当这个函数被用作构造函数时,用new创建的实例,其原型就是这个prototype指向的对象。
• proto:每个对象(包括函数)都有这个属性(非标准但浏览器普遍支持),它是对象的“原型指针”,直接指向该对象的原型。
• constructor:原型对象自带的属性,默认指向该原型对应的构造函数。比如Person.prototype.constructor会指向Person。
举个例子
function Student(){}
Student.prototype.school = "中学";
const student = new Student();
console.log(student.school);
Student.prototype.school = "小学";
console.log(student.school);
3. 原型的出现是为了解决什么问题?
早期的JavaScript没有“类”的概念,如果想让多个对象共享方法,只能手动给每个对象复制一遍,既浪费内存和时间又不好维护。
原型的设计完美解决了这个问题:把需要共享的方法放在构造函数的prototype里,所有实例通过原型链就能访问到,不用重复定义。
4. 原型的数据类型与特殊情况
从数据类型上讲,原型是一个“对象”(准确说是Object类型,除了Object.prototype的原型是null)。
但并不是所有数据类型都有原型:
• 基本数据类型(number、string、boolean等):
通常是没有原型的。
• 引用数据类型(object、array、function等):
都有原型,对象通过 __proto__指向其构造函数的prototype
而函数本身既是对象也是构造函数,有自己的protoype属性,同时通过__proto__指向Function.prototype
• null和undefined:没有原型。
二、原型链:对象属性的“溯源之路”
1. 什么是原型链?
既然原型本身也是对象,那它也有自己的原型——这样一层套一层,就形成了一条链式结构,这就是原型链。
打个比方:就像你在家找剪刀,先翻自己的抽屉(对象自身),找不到就去客厅抽屉(对象的原型),再找不到就去储物间(原型的原型),直到找到或确认家里没有(原型链终点)。
2. 原型链的查找规则
当我们访问一个对象的属性或方法时,JS会按以下步骤查找:
-
先检查对象自身是否有该属性/方法,有则直接使用;
-
若无,就通过__proto__查找其原型;
-
若原型中没有,继续查找原型的原型(proto.proto);
-
以此类推,直到找到Object.prototype(它的__proto__是null,即原型链的终点);
-
若全程没找到,属性返回undefined,方法则报错“xxx is not a function”。
例子
const vehicle = {
wheels: 4,
start() {
return "Engine started";
}
};
const car = {
brand: "Toyota",
__proto__: vehicle
};
console.log(car.wheels);
console.log(car.start());
console.log(car.brand);
三、原型链如何支撑JS的继承机制?
JavaScript的继承是靠原型链继承——让子类的实例通过原型链访问父类的属性和方法,实现代码复用。
继承的核心逻辑
让子类的原型指向父类的实例(或父类的原型),这样子类实例的原型链就能“挂靠”到父类的原型上,从而共享父类的方法。
原型链继承的优势在于灵活——不需要预先定义“类”的关系,通过修改原型链就能动态改变继承关系。这也符合JavaScript“动态语言”的特性,让对象能在运行时灵活共享和扩展功能。
例子
function Animal(){}
Animal.prototype.eat = function(){
console.log("动物吃东西")
};
function Dog(){}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function(){
console.log("狗叫")
};
const dog = new Dog();
dog.bark();
dog.eat();
总结
原型就像对象的“共享基因库”,原型链则是基因的“传递链条”,而继承就是通过这条链条实现的“基因传承”。理解prototype、__proto__和constructor的关系,看清原型链的查找规则,你会发现JS的对象机制其实很精妙。
最后
希望路过的前端的大佬可以给一点指导意见,谢谢。