开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
省流阅读:对象的 __ proto__ 属性 指向其构造函数对象的prototype
技术背景:我们由维基百科对JS的定义说起,首先引用一下英文释义,
JavaScript is a high-level, often just-in-time compiled language that conforms to the ECMAScript standard. It has dynamic typing, prototype-based object-orientation, and first-class functions. It is multi-paradigm, supporting event-driven, functional, and imperative programming styles.
这里我们只关注两个释义,
1.first-class functions
头等函数也就是我们通常所说的“函数是头等公民”,这意味着,函数可以作为别的函数的参数,作为函数返回值,赋值给变量,或者,存储在数据结构中。这样,函数的名字就没有特殊含义,可当作具有函数类型的普通变量来对待,函数与其他数据类型一样,处于平等地位。
JS历史:借鉴Scheme语言,将函数提升到"第一等公民"(first class)的地位;
2.prototype-based object-orientation
翻译成中文:基于原型的面向对象设计。基于原型的编程是面向对象编程的一种方式,JS便是基于这种方式的一种主流开发语言。与之相对应的,基于类的主流开发语言有Java,C++。JS中没有Class的概念,虽然ES6引入类,但实质上这只是基于原型的继承的语法糖而已,并没有引入新的面向对象的继承模型。
基于类的语言,对象或实例(通常)通过类构造器来创建。基于原型的语言,对象通过复制已有对象或者通过扩展空对象创建。在JS中,复制并不是真正的复制一个对象,而是使新对象持有一个原型的引用。
JS历史:借鉴Self语言,使用基于原型(prototype)的继承机制。
JS有两种对象,Object 和 Function
Step1: Object,JS中所实例有对象都有1个__proto__属性,__proto__属性也称为隐式原型,这个属性可看作是对象链接原型对象的‘指针’。__proto__属性是对象所独有的
一个对象的隐式原型指向构造该对象的构造函数的原型。
var foo = {name:'foo',one:1,two:2}
var bar = {three:3}
bar.__proto__ = foo;
这里声明了两个对象,并将其中一个的原型属性指向foo,这样,bar的原型对象就变成foo,也意味着bar可以访问foo中的变量。
bar.one // 输出1
bar.name = 'newFoo' foo.name // 依旧输出 foo
bar对象持有其原型对象的副本,修改其原型的属性,不会导致原有原型对象被修改。
Step2:prototype属性是函数所独有的;prototype则是 Function 对象的属性 prototype也称显式原型,每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。因为函数也是一种对象,所以同时拥有__proto__属性和prototype属性。
扩展:
- 方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法。
2.原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
// 构造函数
function Foo(y) {
this.y = y;
}
// 修改 Foo 的 prototype,加入一个成员变量 x
Foo.prototype.x = 10;
// 修改 Foo 的 prototype,加入一个成员函数 calculate
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
};
// 现在,我们用 Foo 这个原型来创建 b 和 c
var b = new Foo(20);
var c = new Foo(30);
// 调用原型中的方法,可以得到正确的值
b.calculate(30); // 60
c.calculate(40); // 80
图源来自英文文章 dmitrysoshnikov.com/ecmascript/…
Step3:__proto__隐式属性和prototype显式属性的作用
3.1 __proto__属性:当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象寻找,类似JAVA双亲委托机制,一直找,直到__proto__属性为null,再往上会报错,因为null没有原型。
原型链:通过__proto__属性将对象的继承关系连接起来,这条链路就叫原型链。
3.2 prototype属性:让该函数所实例化的对象们都可以找到公用的属性和方法。 普通对象.proto 指向它的构造函数的原型。即,f1.proto === Foo.prototype.
3.3 比较特殊的的是原型对象prototype,它本身也是一个对象,它的构造函数就是Object,所以 函数.prototype.proto === Object.prototype
一图胜千言
以上。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情