新世纪的编程语言中,面向对象可以说是极大方便了开发者,身为后起之秀的javascript,更是借鉴更新,形成了一种具有自己特点的面向对象的方式,巧妙的用了 “基于原型的继承方式”,不必纠结于什么是原型,去想一下,为什么这么设计,就会发现,这是多么巧妙
了解Js继承,就先明白 “为什么说 Js是基于原型链的语言”, 下边先简单介绍一下,Js是如何设计的
Js如何解释prototype
JavaScript 中的每个函数中都有 prototype 属性, 这是Js中函数的一个属性 ,是函数独有的一个属性
var x = function (a, b) {return a * b};
console.log(x.prototype) // 输出 {constructor: ƒ}
上边的代码中,可以看到函数有这一个属性,它指向了一个对象,对象有一个constructor属性。在Javascript 资料中 , 说函数的prototype 属性指向的是“函数的原型对象”, 先不要纠结这是啥,它只是一个名字。 关注一下这个原型对象用处 :
“包含可以由特定类型的所有实例共享的属性和方法”
函数和创建对象
之前文章中提到,利用函数创建对象,
var x = function (a, b) {return a * b};
var xbj = new x();
console.log(xbj); //输出 :{}
上边代码,利用new操作符 ,来调用构造函数,会创建一个对象,其中this可以指向调用函数之后创建的对象。 这里简单说一下,new操作符是用来创建对象,并不是调用函数本身,如下
var person = function (a, b) {
this.name = a;
this.age = b;
};
var zhangsan = new person('zhangsan',21);
console.log(zhangsan);
//输出 :person {name: 'zhangsan', age: 21}
console.log(typeof zhangsan); //输出 :“object”
var lisi = new person('lisi',18);
console.log(lisi); //输出 : person {name: "lisi", age: 18}
上边创建了 zhangsan和lisi两个对象,输出也证明了这一点
从设计师角度考虑,如何使用原型对象
之前的代码,了解了构造函数会有原型对象,构造函数可以创建对象。接下来,倘若构造函数创建的多个对象都需要添加 几个共同属性,比如zhangsan 和lisi 中新增一个属性 country : ‘china’
当然 ,可以直接添加
zhangsan.country = 'china';
lisi.country = 'china';
但是, 试想一下,这只是两个人,假如一百个人,一千个人呢, 在Java中,会考虑把这些多个对象共用的变量放到类的静态量中,实际上,Javascript 也用了有点类似的方式,Javascript是用构造函数创建对象,把多个对象共用的变量放到 构造函数的 原型对象 prototype中,如下
person.prototype.country = 'china'
console.log(lisi.country); //输出 china
console.log(zhangsan.country); // 输出 china
了解函数的原型对象
函数的原型对象, prototype ,其中有一个属性constructor 。 javascript是这样描述:
constructor属性 : 是对象特有的属性,指向这个对象的构造函数, 每个对象都会有,有意思的是,Javascript中 一切都是对象,如下
var obj = {};
var arr = [];
var f = function(){}
console.log(obj.constructor)
//ƒ Object() { [native code] }
console.log(arr.constructor)
//ƒ Array() { [native code] }
console.log(f.constructor)
//ƒ Function() { [native code] }
上边代码也佐证了一切对象都会有构造器属性 constructor 。 仔细观察,constructor属性实际上是指向了每个对象的构造函数,比如{}的构造函数是Object 、[]的构造函数是 Array、函数的构造器函数是 Function
接下来看一下,如果是用new 创建的对象,它的构造函数是:
var person = function(){this.name = '123'};
var bob = new person();
console.log(bob.constructor); //输出 : ƒ (){this.name = '123'}
var tom = new bob.constructor() // 测试用bob对象的constructor属性是否可以创建对象
console.log(tom)//person {name: "123"}
再一次证明了,每个对象都有 constructor属性,指向的是它的构造函数。实际上 这也要求,我们如果想修改两个构造函数创建的对象的父子关系,不要忘了修改 “函数原型对象的constructor属性”
_proto_
创建的对象,我们注意到除了自身属性之外,也有一个_proto_属性,它指向一个对象。
创建的对象有
"_proto_是Js中对象特有的,指向的是它的原型对象"
注意 Js中对象都会有这么一个属性,因此 , 原型对象也会有自己的这一个属性,指向原型对象它的 原型对象 。形成了一个链的东西,就是原型链
说一下 , 原型链
上边截图中,可以清楚看到了原型链,原型链就是
对象中的_proto_,层层上推,一直到顶层Object