JavaScript 系列之原型(一)

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

1、原型

原型是一个对象markdown

image.png

如图所示,咱们来 new 两个 Foo 的实例来看看:app

functionFoo(){

}
let f1 = new Foo()
let f2 = new Foo()
复制代码

1.1 prototype

每一个函数都有一个 prototype 属性(除了 Function.prototype.bind()),该属性指向原型。ide

function Foo(){

}

Foo.prototype.msg = 'hello';
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.msg) // hello
console.log(f2.msg) // hello
复制代码

基本上全部函数都有这个属性,可是也有一个例外函数

let fun = Function.prototype.bind()
复制代码

若是你以上述方法建立一个函数,那么能够发现这个函数是不具备 prototype 属性的。post

当咱们声明一个函数时,这个属性就被自动建立了。ui

function Foo(){}
复制代码

构造函数的 prototype 属性指向原型对象this

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

如上栗子,Foo 函数也是一个对象,该构造函数对象有一个 prototype 属性,指向实例 f1 和 f2 的原型对象即 Foo.prototype 。而在原型对象上挂在的属性和方法都属于公共属性或者公共方法,由全部该构造函数 new 的实例对象所共有,即 f1 和 f2。url

1.2 __proto__

每一个对象都有 __proto__ 属性,指向了建立该对象的构造函数的原型。

console.log(f1.__proto__ === Foo.prototype); // true
复制代码

那原型也是对象,构造函数也是对象,它们的 __proto__ 属性又指向哪里?答案依然仍是指向了建立该对象的构造函数的原型

1.2.1 构造函数的 __proto__

函数也是一个对象,函数的构造函数是 Function ,所以 __proto__ 指向了 Function.prototype

这是每一个对象都有的隐式原型属性,指向了建立该对象的构造函数的原型。其实这个属性指向了 [[prototype]],可是 [[prototype]] 是内部属性,咱们并不能访问到,因此使用 __proto__ 来访问。

由于在 JS 中是没有类的概念的,为了实现相似继承的方式,经过 __proto__ 将对象和原型联系起来组成原型链,得以让对象能够访问到不属于本身的属性。

当咱们使用 new 操做符时,生成的实例对象拥有了 __proto__ 属性。

function Foo(){}
// 这个函数是 Function 的实例对象
// function 就是一个语法糖
// 内部调用了 new Function(...)
复制代码

因此能够说,在 new 的过程当中,新对象被添加了 __proto__ 而且连接到构造函数的原型上。

new 的过程:

  1. 新生成了一个对象
  2. 连接到原型
  3. 绑定 this
  4. 返回新对象

在调用 new 的过程当中会发生以上四件事情,咱们也能够试着来本身实现一个 new,在这以前先来重温一个知识点:

// this指向调用的对象,当用了call后,可以改变this的指向,也就是指向传进来的对象,这是关键
// shift()函数是将数组的第一个值删除,并返回,这里是获得obj
[].shift.call(arguments)

由于 arguments 构造以下,第一个是长度
{length:2,0:'first',1:'second'};
复制代码
function create() {
  // 建立一个空的对象
  let obj = new Object();
  // 得到构造函数:将第一个参数 Person 删除并返回
  let Con = [].shift.call(arguments);
  // 连接到原型
  obj.__proto__ = Con.prototype;
  // 绑定 this,执行构造函数
  let result = Con.apply(obj, arguments);
  // 确保 new 出来的是个对象 return
  typeof result === "object" ? result : obj;
}

function Person(name, age) {
  this.name = name;
  this.age = age;
}
var a = create(Person, "小花", "16");
console.log(a); // Person {name: "小花", age: "16"}
复制代码

对于实例对象来讲,都是经过 new 产生的,不管是 function Foo() 仍是 let a = { b : 1 }

function Foo(){}
// function 就是个语法糖
// 内部等同于 new Function()

let a = { b: 1 }
// 这个字面量内部也是使用了 new Object()
复制代码

1.2.2 原型的 __proto__

原型也是个对象,原型的构造函数是 Object,所以 __proto__ 指向了 Object.prototype,而 Object.prototype 这个原型对象最终指向 null。

1.3 constructor

  • 实例的属性 constructor 指向构造函数
function Person() {

}
var person = new Person();
console.log(person.constructor === Person); // true
复制代码
  • 构造函数的原型的 constructor 会指向这个函数
console.log(Person.prototype.constructor === Person); // true
复制代码
相关文章
相关标签/搜索