- 刚开始学Javascript的时候觉得很简单,其中的东西也就是那是基本的,但是还是太年轻,最近因为面试中常被问到关于原型和原型链的问题,然后自己也是模棱两可的,含含糊糊说不清楚,所以痛下思定,决定好好下一番功夫来搞懂吃透原型与原型链究竟是什么。
关于new
new的过程
- 新生成了一个对象
- 链接到原型
- 绑定 this
- 返回新对象 知道了
new的原理后,也可以自己实现一个new函数:
function myNew() {
// 创建一个空的对象
let obj = new Object()
// 获得构造函数
let Con = [].shift.call(arguments)
// 链接到原型
obj.__proto__ = Con.prototype
// 绑定 this,执行构造函数
let result = Con.apply(obj, arguments)
// 确保 new 出来的是个对象
return typeof result === 'object' ? result : obj
}
先来看几个例子:
- 普通函数
function test(name){
console.log(name);
}
typeof(test) // function
- 使用new新建对象
function test(name){
console.log(name);
}
var te = new test("Hal");
typeof(te) // object
console.log(JSON.stringify(test.prototype)) //{},是个空对象
console.log(JSON.stringify(te.prototype)) //undefined
- 直接声明的函数拥有
prototype这个属性,而new构造出来的函数不存在prototype。
关于prototype
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象 prototype,这个对象就是我们所说的prototype,每一个对象都会从prototype"继承"属性。除了new出来的函数,每个函数都有一个prototype属性,如下,在prototype上可以设置属性,然后打印出一些东西:
function Employee() {}
// prototype是函数才会有的属性
Employee.prototype.name = 'Hal';
var employee1 = new Employee();
var employee2 = new Employee();
console.log(employee1.name) // Hal
console.log(employee2.name) // Hal
console.log(employee1.constructor) // Employee() {}
console.log(employee1.constructor.name) // Employee
console.log(employee1.prototype) // undefined
console.log(employee1.__proto__) // {name: "Hal", constructor: ƒ}
console.log(Employee.prototype) // {name: "Hal", constructor: ƒ}
console.log(Employee.prototype === employee1.__proto__) // true
console.log(Employee.prototype.constructor === Employee) // true
关于__proto__
从刚才的例子中已经可以很清楚地看出了,employee1的__proto__和Employee.prototype是相等的,也就是指向同一个对象,也就是说,实例中有一个__proto__指针指向构造函数的prototype。使用Object.getPrototypeOf与__proto__是同样的效果。
Object.getPrototypeOf(employee1) === Employee.prototype //true
关于constructor
从上面可以看到,原型prototype里面还有一个constructor的属性,然后这个constructor又指向了函数本身。
好像有一点绕,但是看一下下面的图就一目了然了:
总结
-
Object是所有对象的祖先,所有对象都可以通过__proto__找到它 -
Function是所有函数的祖先,所有函数都可以通过__proto__找到它 -
Function.prototype和Object.prototype是两个特殊的对象,由引擎创建,而且Function.__proto__.__proto__是指向Object.prototype的 -
即:
Function.__proto__.__proto__ === Object.prototype // true -
除了以上两个特殊对象,其他对象都是通过构造器 new 出来的 函数的
prototype是一个对象,也就是原型 -
对象的
__proto__指向原型,__proto__将对象和原型连接起来组成了原型链