george-es / Blog

My Blog
0 stars 0 forks source link

你学废了吗——原型到原型链 #74

Open george-es opened 3 years ago

george-es commented 3 years ago

原型

什么是原型?

每一个 JavaScript 对象( null 除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

每个构造函数都有一个原型属性 prototype,它是一个指针,指向一个对象,该对象包含了所有属性的实例和方法,使用原型对象的好处可以让所有对象实例共享它所包含的属性和方法。

至少我们知道了,每个构造函数有个 prototype(原型)属性指向它的原型对象

什么是构造函数?

构造函数和普通函数一样,只不过它被 new 操作符调用了,可以这样理解,被 new 操作符调用的函数就是构造函数,反之就是普通函数

什么是原型对象?

原型对象它包含了所有属性的实例和方法,默认只有 constructor 属性,其他属性都是从 Object 继承而来。通过 new 关键词调用构造函数可以创建一个实例,该实例拥有原型对象上的所有属性和方法。

至少我们知道,每个原型对象都有一个 constructor (构造函数)属性指向构造函数

什么是实例对象?

实例对象内部有个 [[Prototype]] 指针(除了 null),指向原型对象,浏览器中用 __proto__ 属性代替。

至少我们知道,每个实例对象中都有一个 __proto__属性,指向实例对象

缕一缕它们的三角恋关系

实例对象 = new 构造函数
原型对象 = 实例对象.__proto__
构造函数 = 原型对象.constructor
原型对象 = 构造函数.prototype

function Person() {}
let person = new Person()
console.log(person.__proto__ === Person.prototype) // true
console.log(Person === Person.prototype.constructor) // true

写在构造函数中的属性和原型上的属性有什么区别

写在构造函数中的属性实例化后会在实例对象中,而原型上的属性是在原型对象中,实例对象只修改删除自己的属性不会影响到其他实例上的属性

function Person() {
    this.name = 'george' // 构造函数上的属性
}
Person.prototype.age = 18 // 原型上的属性
const person = new Person()
const person1 = new Person()
person.age = 16
console.log(person.age, person1.age);

说说多个对象实例共享原型所保存的属性和方法的基本原理

当代码读取某个对象属性时,都会执行一次搜索,目标是给定名字的属性,搜索首先从对象实例本身开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值,如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性,如果在原型对象中找到了这个属性,则返回该属性的值。

什么是原型的动态性

对原型对象做任何修改都可以立刻从实例上反映出来,这就是原型的动态性。

原型对象的问题

原型模式最大的问题就是其共享的本性导致的

new 一个构造函数发生了什么?

function Foo() {...};
let f1 = new Foo();

以上代码表示创建一个构造函数Foo(),并用new关键字实例化该构造函数得到一个实例化对象f1。虽然是简简单单的两行代码,然而它们背后的关系却是错综复杂的,如下图所示:

image

API

原型链

什么是原型链?

原型链的顶端是 null

原型链是一种机制,指的是 JS 每个对象包括原型对象都有一个内置的[[proto]]属性指向它的原型对象,每个原型对象也有[[proto]]属性,将它们连接在一起就是原型链

image

原型链存在主要是为了实现对象的继承

function Foo() {}
function Foo1() {}
function Foo2() {}
Foo.prototype.__proto__ = Foo1.prototype
Foo1.prototype.__proto__ = Foo2.prototype
const f = new Foo()
console.log('f', f);

f -> Foo() -> Foo1() -> Foo2() -> Object ->null