js面向对象详解

最近比较忙,没怎么更,春困夏乏呀,天太热了。有点不想写代码了,哈哈,就来写博客了哦0..0,今天讲讲那些面向对象的事吧。
一般js有两种开发模式,函数式(又叫过程化,小伙伴们平常用的最多的就是这种模式)和面向对象(oop)(一般多用于插件开发)。
面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统
1.为啥要用面向对象编程?先看例子!
一般创建一个对象方法
var person=new Object()
person.name=”xiaoli” //添加一个name属性并赋值
person.age=”18” //添加一个age属性并赋值
person.run=function(){ //添加一个run()方法
alert(this.name+’can run’)
}
调用:person.run() //输出:xiaoli can run

那么问题了来了,我想创建很多类似person的对象,他们都有各自的名字和年龄,并且有run方法,我难道要一个一个的创建?哦,面向对象来!面向对象自告奋勇!我可以!好好,来你上!我能解决这种重复问题!
面向对象有好几种方法,我们先从最开始低级的工厂模式开始!
工厂模式
function creatPerson(name.age){
var ojb=new Object()
ojb.name=name
ojb.age=age
ojb.run=function(){
alert(this.name+’can run’)
}
return ojb

}
var person1=creatPerson(‘xiaoli’,’18’)
person1.run() //输出:xiaoli can run
大家仔细看这个模式好像就是,写一个creatPerson函数功能就是创建对象,你每创建一个对象调用一次这个函数!工厂模式是解决了我们重复实例化的问题,但是创建不同对象我们都要重复调用这个函数,内存消耗很大,况且函数体识别也是问题!this指向不明确!

`构造函数模式:
底下这个函数称为构造函数,其实和普通函数是一样的,普通函数new一下就会把他内部的this指向新的对象
function creatPerson (name,age){
this.name=name
this.age=age
this.run=function(){
alert(this.name+”can run”)
}
}
var person1=new creatPerson(‘xiali’“18”)//new 操作符实例化对象,其实就是把this指向改到新的对象上,把this指向了person1对象
调用:person1.run()//输出 :xiaoli can run
var person2=new creatPerson(‘xiaowang’,’20’) //实例化
调用:person2.run() //输出:xiaowang can run
哈哈,这样同样就解决了重复去创建多个对象的问题了,我想创建多少个,我直接new一下,然后给参数赋值,我就可以拥有类似的他们的方法和属性哦!而且this指向很明确
那么问题又来了!这个方法也没有解决重复执行构造函数内部代码的问题,内存消耗问题!为了解决这个问题!我们又想出了新办法!
原型
我们创建的每个函数(注意只有函数有这个属性,实例化的对象没有)它都有一个prototype属性,这个属性指向的是自己的原型对象,看例子吧!
function a(name){
this.name=name
this.run=function(){
alert(this.name+’can run’)
}
}
a.prototype是这个函数的原型对象,a函数就被称为他原型对象的子类型,a函数可以继承他原型对象的所有的属性和方法
a1=new a(‘呵呵1’)
既然每次实例化一个对象的时候我们都要重复执行构造函数里的代码,为什么我们不把经常不改变的方法直接添加到他的原型上呢?添加到原型上我们就不用每次实例化的时候就不会重复执行一些方法和属性了的代码了,这样内存消耗就小了很多
看代码!我们可以这样
function a(name){
this.name=name //把经常改变的属性和写到构造函数里
}
a.prototype.run=function(){
alert(this.name+’can run’)
}
var a1=new a(‘小李’)
a1.run() //输出:小李can run 因为new的时候只执行构造函数里的代码,同时子类型继承原型的所有方法和属性,这样解决了内存消耗的问题
所以实际中我们更多是用构造函数和原型继承一起去实现面向对象的!

最后说下apply和call是个啥玩意,其实这两个方法都是函数体的父级原型的方法,函数体只是继承了而已,

function add(a,b){
  alert(a+b)
} //每个函数体方法都有个原型父级,add.prototype对象,这个对象不本身就有apply和call方法,还有arguments(代表的是函数参数的数组)。所以子级可以直接调用
function getAdd(a,b){
  add.call(this,a,b) //call第一个参数是上下文执行环境的对象window,也可以用this,后面的参数就是依次为改函数的本身参数
}
get(1,1) //输出2

function getAdd(a,b){
  add.apply(this,arguments) //call第一个参数是上下文执行环境的对象window,也可以用this,后面的参数是一个arguments代表的就是改函数体的参数数组
}
get(1,1) //输出2

总结:apply和call方法功能一样,仅仅是用的时候一个必须所有参数元素,一个是参数的arguments,其实这真的没啥可比性这两个,因为就是本身两个不同的方法而已,每个方法都有自己的使用规则,恰巧他们实现了相同的功能

猜你喜欢

转载自blog.csdn.net/qq_37983691/article/details/77715205