JavaScript | 原型与原型链

发布于:2025-04-17 ⋅ 阅读:(36) ⋅ 点赞:(0)

原型与原型链

深入理解原型和原型链

每个对象(object)都有一个私有属性指向另一个名为原型(prototype)的对象。原型链:原型对象也有一个自己的原型,层层向上直到找到 null。原型链决定了对象属性的访问方式。

在控制台输出一个对象,都能看到有一个名为[Prototype]的对象,打开后也能找到在这个对象中有__proto__属性

输出一个函数,除了有上面的带方括号的Prototype,还有一个不带方括号的prototype属性,这些属性都叫原型

什么是原型

遵循 ECMAScript 标准,每一个对象上的 [[Prototype]](内置属性)表示原型,注意:并非所有的对象都有原型。为了方便理解,把**[[Prototype]]** 也称为 隐式原型

const o1 = {}
const o2 = new Object()
const o3 = Object.create({null})

console.log(o1)
console.log(o2)
console.log(o3)

返回结果是o1与o2都有原型,o3没有,这是因为Object.create()方法会把传入的参数作为原型

原型的访问可以通过对象的__proto__和Object.getPrototypeOf()来访问

var obj = {}
obj.__proto__ === Object.getPrototypeOf(obj) // true
console,log(obj.__proto__)
console,log(Object.getPrototypeOf(obj))

原型的原型

console.log(obj.__proto__.__proto__)// null

原型链的顶端:null

原型的主要作用: 实现继承

const parent = {
    a: 1,
    fn() {
        console.log('父级的方法')
    }
}

const child = {}
// 把parent赋值给child的隐式原型
child.__proto__ = parent 
console.log(child.a)
child.fn()
  • 输出child的a属性与调用fn方法,发现都能使用。说明child可以从原型上继承到parent的属性与方法
构造函数的prototype

函数的本身(除了箭头函数外)都存在一个prototype属性,该属性是在给定函数被用作构造函数时分配给所有对象实例的 [[Prototype]],为了方便理解,把构造函数的prototype 也称为 显示原型

var fn = function() {}
console.dir(fn)

var f = new fn()
f.__proto__ === fn.prototype // true

实例的原型与构造函数的原型是全等的

构造函数中有一个prototype属性,这个属性指向的就是这个函数的显式原型

寻找这原型的原型:

f.__proto__.__proto__ === Object.prototype// true

所以f的原型的原型,是由Object的原型构造出来的

console.log(f.__proto__.__proto__.__proto__)// null顶端

实例中有constractor属性,指向的是这个实例的构造函数

console.log(f.constractor === fn)// true

实例可以通过这个属性来找到其构造函数

构造函数的原型的constractor属性指向的是其本身

console.log(fn.prototype.constractor === fn)// true

总结:

  • 构造函数通过new创建f,f通过constractor属性访问到构造函数fn
  • 构造函数fn的prototype属性指向了fn的原型,也是实例f通过__proto__属性访问到f的原型
  • 实例f的原型通过constractor属性也可以访问到构造函数fn
  • 实例f的原型是Object通过new的方式创建的
  • Object通过prototype属性能找到Object原型,即f的原型的原型
  • 实例f的原型可以用__proto__属性继续访问,也可以继续用这种方法接着访问到顶端的null

构造函数是函数,有显式原型,同时也是对象,就有隐式原型

构造函数的隐式原型是Function的prototype(Function是一个关键字)

所有函数的构造函数都是Function,所以构造函数的原型可以用fn.__proto__访问到

const fn = function() {}
fn.__proto__ === Function.prototype// true

也可以用Function的prototype属性访问到

console.log(Function.__proto__)// 

需要注意的是,funtion的__proto__(隐式原型)与Funtion.prototype(显示原型)指的是同一个东西

总结:

什么是原型链

原型链决定了对象属性的访问方式,对象寻找属性会从本身开始查找,本身找不到会继续沿着原型链往原型上去找,直到找到原型链顶端null,都找不到就返回undefined

  • 获取属性的情况
var obj = { foo:1 }
obj.__proto__.foo = 2// 在原型上加一个属性foo,值为2
console.log(obj.foo)// 1从本身找
  • 赋值属性的情况
var obj = { foo:1 }
var obj1 = Object.create(obj)
obj1.foo = 2// 给foo属性赋值
console.log(obj1)

obj1以obj为原型,所以obj的foo属性的属性值1,是在obj1的原型上;obj1.foo=2是给obj1创建foo属性赋值为2,因为本身没有,所以创建;

var obj = { foo:[1] }// 把值改为一个数组
var obj1 = Object.create(obj)
obj1.foo[0] = 2// foo属性的值的0号位赋值
console.log(obj1)

obj1以obj为原型,所以obj的foo属性的属性值[1],是在obj1的原型上;obj1.foo[0]在obj1本身找不到,所以会往原型上找,发现原型obj有这个属性,所以obj这个属性值被修改为2

两种写法,第二种却是寻找,因为obj1.foo[0] = 2这里的写法foo[0]这个寻找元素的写法,所以是在查找对应元素,所以不会创建新属性,本身找不到就往上找


网站公告

今日签到

点亮在社区的每一天
去签到