原型是 JavaScript 巧妙的设计,它很是容易理解。都 2020 年了,看完这篇但愿你之后不须要再重复学习 JavaScript 原型了。若有不当之处,恳请指点一二!函数
下面是相关单词及其翻译,紧紧记住它们就成功一半了。学习
function Drink() {} const a = new Drink() console.log(a.constructor) // ƒ Drink() {}
a 是由函数 Drink 构造而来的。测试
简单写点代码,后面全是 console.log
。ui
function f() { this.a = 1 this.b = 2 } const o = new f() f.prototype.b = 3 f.prototype.c = 4
o 是 new f()
返回的结果,不妨回顾一下当执行 new f()
时, new 操做符对函数 f 作了些什么事。this
var obj = Object.create(null)
。obj.__proto__ = f.prototype
。new Foo
等同于 new Foo()
,也就是 f 不带任何参数调用的状况; 将步骤 1 建立的对象做为 this 的上下文(将 this 绑定到新建立的对象 | f 函数中的 this 的指针替换成 obj) ,f.call(obj)
。对于一个函数,若是不使用
new
操做它,它只是一个正常的函数;使用new
操做符仅仅改变了它的 this 指向且在函数内部隐式地建立了一个对象,而后再称之为 “构造函数”。仅此而已。prototype
若是你对第三步中的操做有困惑,看几个简单的例子:翻译
function f() { this.a = 1 this.b = 2 } f() console.log(f.constructor) //ƒ Function() { [native code] }
function f() { this.a = 1 this.b = 2 } const o = new f() console.log(o.constructor) // ƒ f() { // this.a = 1 // this.b = 2 // }
function f() { console.log(this) // window this.a = 1 this.b = 2 } f()
function f() { console.log(this) // f {} this.a = 1 this.b = 2 console.log(this) // f {a: 1, b: 2} } new f()
const drink = { name: 'Coca Cola', color: 'black', price: '3.5', intro: function () { console.log(`名称:${this.name},颜色:${this.color},价格:${this.price}`) }, } const computer = { name: 'Orange Juice', color: 'orange', price: '4', } drink.intro.call(computer) //名称:Orange Juice,颜色:orange,价格:4
确保上面的内容你能十分清晰,不然不要进行下面的内容。设计
console.log(o.b) // 2
o 的值是经过 new f()
获得的对象,this 指向这个对象,函数中给 this 添加了属性 b 为其赋值为 2,并将他返回。因此 这里打印出 2。f.prototype
是没法被访问到的,这种状况还被称之为 property shadowing ---属性遮蔽。指针
console.log(o.c) // 4 console.log(o.__proto__.c) // 4 console.log(o.__proto__ === f.prototype) // true
函数中并无给 this 添加 c 属性并为其赋值 4,可是打印 o.c 返回 4。经过上文你已经知道 constructor 是干什么的了:code
console.log(o.constructor.prototype.b) // 3
o 是由函数 f 构造的,o.constructor
返回函数 f,因此o.constructor.prototype === f.prototype
, f.prototype
返回什么呢?上面初始代码中直接写好的,如今能够翻上去看看 f.prototype
,因此 o.constructor.prototype.b
返回 3。查找对象上的属性就是先找自身再经过 __proto__
一层一层往上找的:
prototype
上也有,属性遮蔽不会忘了吧;__proto__
找但没找到,会返回 undefined
;为何呢?console.log({}.constructor) // ƒ Object() { [native code] } console.log({}.__proto__ === Object.prototype) // true console.log(Object.prototype.__proto__) // null
看到这里,应该十分清晰了。这就是最终为何会返回 undefind 的缘由:Object.prototype.__proto__
指向 null。
作一个简单又不给你解释的小练习吧!
console.log(o.b) console.log(o.__proto__.b) console.log(o.d)
// 2 // 3 // undefined
对于 Object.prototype.__proto__
:
若是看完仍是不太明白,动手试一试吧!我把本文用到的代码片断放到此处供你快速拷贝。
function f() { this.a = 1 this.b = 2 } const o = new f() f.prototype.b = 3 f.prototype.c = 4 console.log(o.b) // 2 console.log(o.c) // 4 console.log(o.__proto__.c) // 4 console.log(o.__proto__ === f.prototype) // true console.log(o.constructor.prototype.b) // 3 console.log(o.b) // 2 console.log(o.__proto__.b) // 3 console.log(o.d) // undefined console.log({}.constructor) // ƒ Object() { [native code] } console.log({}.__proto__ === Object.prototype) // true console.log(Object.prototype.__proto__) // null // --------- other -------- console.log(o.__proto__) // {b: 3, c: 4, constructor: ƒ} console.log(o.__proto__.__proto__ === Object.prototype) // true console.log(Object.prototype.__proto__) // null console.log(o.__proto__.__proto__.__proto__) // null console.log(f.prototype.__proto__ === Object.prototype) // true