面向对象的语言有三个基本特征:封装、继承、多态。 ————这是我以前学Java的时候印象最深的一句话。
现在流行的高级语言越来越多,那到底什么是面向对象?
面向对象是相对与面向过程来说的(C语言就是一门面向过程编程的语言)
。面向对象编程的思想中,有两个类和对象
两个概念。
我们知道ECMAScript中没有类的概念
,所以,JavaScript有别于传统的基于类的面向对象语言,JavaScript的面向对象和Java等高级语言的面向对象不同点在于,它没有抽象、继承、重载等面向对象语言的功能,而是形成了一种基于原型的面向对象
。
原型是什么
在JavaScript中,每一个函数都有原型。
JS中一切皆是对象,原型实质上也是一个对象。JS中所说的原型,全称叫做原型对象。当定义一个函数时,JavaScript就会在计算机内存上生成一个对应的原型对象。这个函数会有一个默认的prototype属性,prototype的值指向的就是内存上对应的原型对象
。
function Fn(){};
Fn.prototype.name = '李四';
Fn.prototype.sayHello = function (){
alert('你好!');
}
console.log(Fn.prototype);
通过函数Fn的prototype属性,可以给函数对应的原型对象添加属性和方法。
除了通过prototype添加的name属性和sayHello方法之外,上面的图片中显示在原型上还有一个constructor属性,constructor的值指向的是当前原型对象对应的函数Fn。这就形成了一个简单的链式循环。
console.log(Fn === Fn.prototype.constructor); // true
JavaScript中,可以通过构造函数和new关键字来创建对象,通过这种方式创建出来的对象都具有相同的属性和行为,比如:
function Fn(){};
Fn.prototype.name = '张三';
Fn.prototype.sayHello = function (){
return '你好,我是' + this.name + '!';
}
var fn = new Fn();
var fn2 = new Fn();
console.log(fn.name); // 张三
console.log(fn.name === fn2.name); // true
console.log(fn.sayHello === fn2.sayHello); // true
上面代码中,fn和fn2两个实例对象都是通过构造函数Fn实例化出来的,在这两个实例对象中,每个对象都有__proto__
属性,指向了创建该对象的构造函数Fn的原型,所以它们共享相同的属性和方法。
其实这个属性指向了[[prototype]],但是[[prototype]]是内部属性,我们并不能访问到,一般我们使用_proto_来访问。
通过下面这个图可以看到,fn和fn2的隐式原型__proto__对应的值都是其构造函数Fn的原型,所用fn.sayHello === fn2.sayHello结果为true,因为这两个方法指向的是同一个对象。
console.log(fn.__proto__ === Fn.prototype); // true
console.log(fn2.__proto__ === Fn.prototype); // true
console.log(fn.__proto__ === fn2.__proto__); // true
原型链
在JavaScript中,一切皆是对象,对象之间往往会通过__proto__链接在一起,这种现象被称为原型链。
JavaScript中,每个对象都有一个属性:__proto__
,这个属性指向该对象的原型A,同样的道理,这个原型对象A也会有一个__proto__
(原型对象也是一个对象),原型对象A的__proto__
属性会指向它的原型对象B,原型对象B的__proto__
属性又会指向它的原型对象C,在JavaScript中,这种现象叫做原型链。
每个对象,都会从原型中继承属性,所以,JS通过这种原理实现了基于原型的继承。
下图是一个完整的原型链示意图。(箭头颜色没啥特殊含义,只是为了表示指向,Enmmm~~~,原谅我这个手残吧。)
在原型链中,有两个特殊的对象,Object
和Function
。
通过上面的示意图可以看到,所有的构造函数的__proto__都指向Function对象的原型(即Function.prototype),就连Function对象本身的__proto__属性也指向Function.prototype。
所有原型对象的__proto__属性都指向Object对象的原型(Object.prototype)。
Object.prototype.proto = null。