这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战数组
原型是一个对象markdown
如图所示,咱们来 new 两个 Foo 的实例来看看:app
functionFoo(){
}
let f1 = new Foo()
let f2 = new Foo()
复制代码
每一个函数都有一个
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
__proto__
每一个对象都有
__proto__
属性,指向了建立该对象的构造函数的原型。
console.log(f1.__proto__ === Foo.prototype); // true
复制代码
那原型也是对象,构造函数也是对象,它们的 __proto__
属性又指向哪里?答案依然仍是指向了建立该对象的构造函数的原型。
__proto__
函数也是一个对象,函数的构造函数是 Function ,所以
__proto__
指向了Function.prototype
。
这是每一个对象都有的隐式原型属性,指向了建立该对象的构造函数的原型。其实这个属性指向了 [[prototype]]
,可是 [[prototype]]
是内部属性,咱们并不能访问到,因此使用 __proto__
来访问。
由于在 JS 中是没有类的概念的,为了实现相似继承的方式,经过 __proto__
将对象和原型联系起来组成原型链,得以让对象能够访问到不属于本身的属性。
当咱们使用 new 操做符时,生成的实例对象拥有了 __proto__
属性。
function Foo(){}
// 这个函数是 Function 的实例对象
// function 就是一个语法糖
// 内部调用了 new Function(...)
复制代码
因此能够说,在 new 的过程当中,新对象被添加了 __proto__
而且连接到构造函数的原型上。
new 的过程:
在调用 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()
复制代码
__proto__
原型也是个对象,原型的构造函数是 Object,所以
__proto__
指向了Object.prototype
,而Object.prototype
这个原型对象最终指向 null。
function Person() {
}
var person = new Person();
console.log(person.constructor === Person); // true
复制代码
console.log(Person.prototype.constructor === Person); // true
复制代码