js的原型和原型链

433 阅读3分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

是什么?

每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性
通过原型这种机制,JavaScript 中的对象从其他对象继承功能特性;这种继承机制与经典的面向对象编程语言的继承机制不同
原型:__proto__\ 原型对象:prototype

为什么?

下面是MDN上的解释,我也已经完全理解,我想用自己的语言去表达,但是,我感觉下面这些已经很精简了
JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象(prototype),对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain) ,它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。
在传统的 OOP 中,首先定义“类”,此后创建对象实例时,类中定义的所有属性和方法都被复制到实例中。在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。
如果我们了解继承,这是我们必须得了解的。

怎么做?

那我们都怎么使用这种关系呢?
可以看下面的代码

function Person() {

}
Person.prototype.name = 'xiaoqiang';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // xiaoqiang
console.log(person2.name) // xiaoqiang

在上面的例子中,Person是一个构造函数,要创建出一个实例对象,必须得用new这个关键字

构造函数和实例原型之间的关系

Person(构造函数) ---prototype---> Person.prototype(实例原型)

console.log(person1.__proto__ === Person.prototype); // true

constructor,每个原型都有一个 constructor 属性指向关联的构造函数。

image.png

console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
function Person() {

}

Person.prototype.name = 'xiaoqiang';

var person1 = new Person();

person1.name = 'xiaopei';
console.log(person1.name) // xiaopei

delete person1.name;
console.log(person1.name) // xiaoqiang

就像上面说的,在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接,之后通过上溯原型链,在构造器中找到这些属性和方法。
在删除了person1上name这个属性之后,就找不到了,就会往上寻找,也就是构造函数的原型对象上,所以,就这样找到了xiaoqiang
那么如果上一层也找不到呢?原型的原型又是什么? image.png

可以看到,原型的原型是Object的原型对象,如果在Object的原型对象上还找不到的话,就会继续往上找,但已经到头了,Object的原型对象的原型是null

null 表示“没有对象”,即该处不应该有值。

所以 Object.prototype.proto 的值为 null 跟 Object.prototype 没有原型

es6的class

es6提供了更接近传统语言的写法,引入了Class这个概念,其实就是个语法糖,原理还是原型。

使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

class Bar {
  doStuff() {
    console.log('stuff');
  }
}

const b = new Bar();
b.doStuff() // "stuff"