一篇文章带你深入原型和原型链

JS创建对象的方法

es6中引入了class关键字,能通过类来创建对象,类是对象的模板,定义了所有对象通用的属性和方法。
class创建:

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log('Hello ' + this.name);
  }
}

let person1 = new Person('John', 30);
let person2 = new Person('Jane', 25);

在es6之前是通过对象字面量或者构造函数来创建对象
对象字面量创建:

let person = {
  name: 'John',
  age: 30,
  greet: function() {
    console.log('Hello ' + this.name);
  }
};

构造函数创建:
构造函数本质上是普通的函数,但当我们使用 new 运算符调用它时,它就变成了一个构造函数,可以用来创建新的对象。通常我们将函数名大写用于区分构造函数和普通函数

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log('Hello ' + this.name);
};

let person1 = new Person('John', 30);
let person2 = new Person('Jane', 25);

构造函数和 new 运算符

当我们调用函数的构造方法时,js会默认执行以下步骤:

  1. 创建一个空对象
  2. 将新对象的__proto__ 属性指向构造函数的 prototype 属性。
  3. 执行构造函数中的代码,将 this 绑定到新对象,并为它添加属性。
  4. 如果构造函数没有显式返回对象,new 表达式会返回新创建的对象。

this 关键字指向新创建的实例对象。构造函数负责将传入的参数赋值给实例对象的属性。

原型与原型链

当我们使用了构造函数创建了对象时,我们发现我们没有定义方法,假如在Person构造方法里面定义方法,那么在每次实例化时都会新创建一个方法,而我们要的是通用的方法,这时候就要用到原型。
原型:
每一个函数(包括构造函数)都有一个 prototype 属性,指向一个对象。这个对象上通常会定义函数的方法。通过原型,所有实例都可以共享方法,而不需要每个实例都创建自己的方法,从而提高内存使用效率。

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log('Hello ' + this.name);
};

let person1 = new Person('John', 30);
let person2 = new Person('Jane', 25);

person1.greet(); // 输出 'Hello John'
person2.greet(); // 输出 'Hello Jane'

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

在这里插入图片描述

那么实例是怎么做到能够调用原型中的属性的呢?
这是每一个JavaScript对象(除了 null )都具有的一个属性,叫proto ,这个属性会指向该对象的原型。

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

在这里插入图片描述

原型也能有指向构造函数倒是有的,这就要讲到第三个属性:constructor,每个原型都有一个 constructor 属性指向关联的构造函数。

function Person() {
}
console.log(Person === Person.prototype.constructor); // true

注意:只是默认的原型指向构造函数指向本身,假如你修改了原型,那么就不对了。

在这里插入图片描述

原型链:
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止

  1. 首先查找对象本身的属性。
  2. 如果没有找到,查找该对象的原型(__proto__)。
  3. 如果仍然没有找到,继续查找原型的原型,直到找到 null 为止。

对象默认的原型对象是 Object.prototype。每当你创建一个普通对象时,它的原型指向 Object.prototype。这意味着对象可以继承 Object.prototype 上定义的属性和方法,例如 toString()hasOwnProperty() 等。
其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 proto 指向构造函数的 prototype ,而那 Object.prototype 的原型是那 Object.prototype 的原型是null,所以我们再更新下关系图:

在这里插入图片描述

注意:
proto ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.proto 时,可以理解成返回了 Object.getPrototypeOf(obj)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值