You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constNEW=function(){letfn=Array.prototype.shift.call(arguments);letobj=Object.create(fn.prototype);leto=fn.apply(obj,arguments);returntypeofo==='object' ? o : obj;}
JavaScript面向对象小结
面向对象的语言有三大特征:
封装
、继承
、多态
。所谓封装,就是将客观事物封装成抽象的类,并且类可以把自己的数据和方法让指定的类或对象操作,比如有些属性和方法是私有的,不能被外界访问。通过封装,可以对对象内部数据提供不同级别的保护。
所谓继承,就是可以让某个对象获得另外一个对象的属性或方法。其概念的实现方式可分为两类:实现继承和接口继承:实现继承是指直接使用基类的属性和方法而无需额外编码能力;接口继承是指仅使用属性和方法的名称,但子类必须提供实现的能力。
所谓多态,就是指一个类实例的相同方法在不同情形有不同的表现形式,使得具有不同内部结构的对象可以共享相同的外部接口。
在JavaScript,同样支持以上的的三个特性。但是,由于在ES5及之前的标准中没有引入
class
关键字,所以其面向对象的功能需要借助原型链来实现。封装
通过构造函数封装:
构造函数和普通函数别无二致,它用来初始化对象。在命名规范中,它的首字母需要大写。
通过构造函数添加属性和方法,实际上就是通过
this
添加属性和方法,因为函数内的this
总是指向当前对象。在实例化对象时,都会复制一份属性和方法。如果构造函数内的属性和方法不是通过
this
添加的,那么该属性和方法就是私有属性和私有方法,其实例无法直接访问。而通过this
添加的方法又称为特权方法,通过它可以让实例访问私有属性和私有方法。继承
ES5继承
虽然没有
class
,但是由于JavaScript的函数作用域(函数外部无法当问函数内部的变量),我们可以借此模拟class
,将属性和方法都保存在一个函数中。原型链继承
将方法绑定在原型链中,该方法就是对象的公有方法,可以被子对象引用。
使用原型链继承,每次创建一个子类实例,都需要重复地执行
new
操作。并且,由于原型链继承里面使用的都是同一个内存的值,假如修改其中一个子类实例继承的属性,将会影响到其他的子类实例:构造函数继承
通过构造函数继承,可以避免实例对共享数据的影响,同时可以在子类中向父类传参:
组合继承
由上两种继承方式可知,原型链实现的继承都是复用同一个属性和方法,构造函数实现的继承都是独立的属性和方法。我们可以同时结合这两种继承方式,在原型上定义方法实现函数复用,通过构造函数有使得每个实例都有自己的属性:
原型式继承
这种方式是模拟
Object.create
,将传入的对象作为创建的对象的原型:和原型链继承方式一样,不同实例也是使用同一内存的数据,可能会造成污染:
在上述代码中,修改了实例
person1
的age
属性,但是不会影响到person2
的age
属性,这是因为person1.age = 20
的操作并未改变原型上的age
。在查找对象上的属性时,总是优先查找实例对象,没有找到的情况下再查找原型对象上的属性,实例对象和原型对象上如果有同名属性,优先取实例对象上的值。寄生式继承
创建一个仅用于封装继承的函数,其内部辅以属性和方法,最终返回对象:
寄生组合继承
稍微封装一下:
ES6继承
在ES6中,引入了
class
和extends
概念,用来实现对象继承:子类必须要在
constructor
中调用super
,否则创建实例时会报错,因为子类没有自己的this
对象,而是继承自父类的。在调用super
后,子类才能使用this
。这样就体现出和ES5的不同:ES6的静态方法和静态属性
在ES6中,假如我们用
static
来修饰对象内的方法,那么该方法就是静态方法,它只能通过直接调用类来使用,而不能被实例调用,同时它是可以被子类继承使用的:甚至,还可以通过
super
来调用父类的静态方法:静态属性是指类本身的属性,而不是定义在实例对象(
this
)上的属性,所以我们可以这样:当然,在ES6中,可以通过
static
来修饰以实现静态属性:ES6本身没有私有方法和私有属性的具体实现标准,我们可以通过某种方式来达到想要的效果,详情可以参考: ECMAScript6入门 和 ES6 系列之私有变量的实现
当我们new了一个实例,前后发生了什么?
比如
var child = new Child()
:child.__proto__ = Child.prototype
,将新创建的对象的__proto__
指向构造函数的prototype
this
指向新创建的对象模拟
new
:多态
从一个父类继承出来的子类有不同的形态:
The text was updated successfully, but these errors were encountered: