JavaScript.Part.2 JavaScript原型链

1. 专业名词理解

  1. js是以对象为驱动编写的,即一切皆对象,所有数据都是对象。
  2. 要理解原型链,就是理解函数、原型对象、实例对象之间的关系。
  3. constructor一般称为构造函数属性,指向函数本身。
  4. prototype一般称原型对象属性,指向函数的原型对象。
  5. __proto__我下面称为原型属性,指向原型对象。
  6. [[Prototype]]我下面称为原型链属性,指向原型对象。
  7. 原型链:每个JavaScript对象都有一个内部属性,称为[[Prototype]],它指向另一个对象。这个被指向的对象就是当前对象的原型。当试图访问一个对象的属性或方法时,如果该对象本身没有这个属性,JavaScript引擎会沿着原型链向上查找,直到找到这个属性或直到原型链的尽头Object.prototypenull(因为null的原型是undefined)。

2. 函数

原型对象属性prototype与构造函数属性constructor
  • 函数上的原型对象属性prototype指向函数的原型对象,原型对象上的constructor指向函数,他们是循环引用的。
    image
  • 上图中,Foo,Object,Function都是函数,Object,Function是内置函数,Foo是自定义的函数。
  • 原型对象属性prototype只存在于函数上。
  • Foo.prototype.constructor === Foo
原型属性__proto__与原型链属性[[Prototype]]

在JavaScript中,__proto__[[Prototype]] 密切相关,但它们之间存在关键的区别:

  1. [[Prototype]]:这是一个对象的内部属性,由JavaScript引擎管理,它指向对象的原型。这个属性对开发者是不可见的,不能直接访问或修改。[[Prototype]] 的值决定了对象的原型链,即在查找属性和方法时的搜索路径。
  2. __proto__:这是ECMAScript规范中定义的一个访问器属性,它提供了对对象内部 [[Prototype]] 属性的访问。__proto__ 允许开发者在代码中读取和设置对象的原型。在非严格模式下,__proto__ 可以用来读取和设置对象的原型。然而,在严格模式下,直接修改 __proto__ 可能会引发错误。

关系和区别:

  • 访问和修改__proto__ 提供了对 [[Prototype]] 的访问,但它是 [[Prototype]] 的一个外部表现,而不是 [[Prototype]] 本身。通过 __proto__,开发者可以读取和(在某些情况下)设置对象的原型。
  • 内部与外部[[Prototype]] 是内部的,不可直接访问;__proto__ 是外部的,通过它来间接访问 [[Prototype]]
  • 规范与实现[[Prototype]] 是由ECMAScript规范定义的,而 __proto__ 是一个实现细节,虽然被广泛支持,但在严格模式下使用时需要谨慎。

总之,__proto__[[Prototype]] 的一个访问器,它使得开发者能够以一种可控的方式与对象的原型链交互。然而,由于其可能带来的副作用,使用时应遵循最佳实践,尤其是在严格模式下编程时。
使用方法获取原型对象,Object.getPrototypeOf(Foo) === Foo.__proto__

原型对象、实例对象上存在__proto__,函数上也存在__proto__,因为函数也是实例对象,Function的实例对象

image

  • Foo.__proto__ === Function.prototype
  • Object.__proto__ === Function.prototype
  • Function.__proto__ === Function.prototype

3. 原型链:原型对象之间的关系

image

  • Foo.prototype.__proto__ === Object.prototype
  • Object.prototype.__proto__ === null
  • Function.prototype.__proto__ === Object.prototype

4. 实例对象的原型链

image

  • f.__proto__ === Foo.prototype
  • Foo.prototype.__proto__ === Object.prototype
  • Object.prototype.__proto__ === null

5. new运算符的原理

在JavaScript中,new 关键字用于创建一个由构造函数定义的新对象。使用 new 关键字时,会经历以下步骤:

  1. 创建新对象:首先,new 会创建一个空的简单JavaScript对象,并且会设置该对象的 [[Prototype]] 属性,让它指向构造函数的 prototype 属性所指向的对象。
  2. 绑定 this:然后,构造函数被调用,而 this 关键字被绑定到上一步创建的新对象。这意味着构造函数内部的 this 现在指向新创建的对象。
  3. 执行构造函数:构造函数的代码开始执行。构造函数通常会设置新对象的属性和值。
  4. 确定返回值:构造函数执行完毕后,如果构造函数显式返回一个对象,则返回该对象。如果构造函数没有返回对象,或者返回的是基本类型值,new 表达式则返回新创建的对象。
//new的实现
var new2 = function (func) {
    var o = Object.create(func.prototype);    //1.创建新对象,并设置原型
    var k = func.call(o);             //2.绑定this 3.执行构造函数
    if (typeof k === 'object') {         //4.确定返回值
        return k;
    } else {
        return o;
    }
}

6. 总结

image

  1. 函数与原型对象的关系
    • Foo.prototype.constructor === Foo
    • Object.prototype.constructor === Object
  2. 函数与函数的关系
    • Foo.__proto__ === Function.prototype
    • Object.__proto__ === Function.prototype
    • Function.__proto__ === Function.prototype
  3. 原型链:原型对象与原型对象的关系
    • f.__proto__ === Foo.prototype
    • Foo.prototype.__proto__ === Object.prototype
    • Object.prototype.__proto__ === null
    • Function.prototype.__proto__ === Object.prototype
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值