关于JavaScript面向对象

JavaScript面向对象

今天我们来介绍一下JavaScript的面向对象部分,那么学过js的朋友应该都知道,关于js面向对象部分是有一点乱的,并没有像java,python之类的有一些比较明确的规范,当然,在之后的ES6的部分还是做了一些完善。

创建对象的几种方式

js不同于强类型语言,关于创建对象它有以下几种方式:

一、字面量方式创建对象

字面量创建对象方式实际上就是实例化创建,代码如下:

var obj = {
		name : '张三',
		age : 20,
		sex : '男',
		run : function(){
			console.log('我正在运动')
		}
	}
	obj.run();
	console.log(obj);
	//不需要使用new,因为它本身便是实力化对象
	//这种方式创建对象时较为繁琐,当需要实例的对象过多时不适用
二、自定义构造函数创建对象
function obj(name,age){
		this.name = name;
		this.age = age;
		this.run = function (){
			console.log('我正在运动');
		}
	}
	var a = new obj("张三",'20');
	a.run();//'我正在运动'
	console.log(a.name);//张三
	console.log(a.age);//20
三、工厂模式创建对象

工厂方式实际上是利用了js原生的Object对象

function Person(name,age){
		var obj = new Object();
		obj.name = name;
		obj.age = age;
		obj.run = function (){
			console.log('我正在运动');
		}
		return obj;//返回该对象
	}
	var a = new Person("张三",'20');//创建新的对象
	a.run();//‘我正在运动’
	console.log(a.name);//张三
	console.log(a.age);//20
四、 使用ES6规范创建对象

关于ES6的创建对象的语法格式就和java之类的强类型语言相似了,或者说js进行了一个模仿,代码格式如下:

class Person{
		constructor (name,age){
			this.name = name;//属性
			this.age = age;
		}//构造函数
		run(){//方法
			console.log(this.name + '正在运动')
		}
	}
	var a = new Person('张三',20);//实例化对象
	console.log(a.age);//20
	console.log(a.name);//张三
	a.run();//张三正在运动

js在ES6面向对象当中引入了class关键字,用来进行关于类的定义,那么constructor里面是构造函数的书写,相信大家都理解,这里不过多说,关于run方法的书写,这里是es6语法当中的一种字面量的简要写法。

当然除了以上几种方式,还有些混合模式之类的,不常用也就不做解释。

对象的继承

对于面向对象的语言来说,面向对象的三个部分:封装,继承,多态是必不可少的。但是在js当中并不具备多态这个特性,它并不像java等强类型语言具有方法的重载和重写等功能,因此并不具备多态,因此它是基于面向对象的语言,但并不面向对象,这一点大家要理解清楚。

那么接下来我们讲解一下在js中关于继承的几种方式:

一、通过原型链实现继承
function Animal(age){
    this.age = age;
    this.eat = function(){
      console.log('吃点什么东西吧')
    }
  }
  function CatClass(name,color){
    this.name = name;
    this.color = color;
    this.sleep = function (){
      console.log('睡一觉吧,太累了')
    }
  }
  CatClass.prototype = new Animal(18);//对原型链进行赋值,更改
  var b = new CatClass('小黑','black');
  b.sleep();//睡一觉吧,太累了
  b.eat();//吃点什么东西吧
  console.log(b.age)//18

大家看到了,上面的代码就是通过对原型链的更改实现了,使用b对象调用eat()方法,b对象是CatClass创建出来的,却调用了Animal当中的eat()方法,因此实现了继承。原型链赋值那里需要注意,赋的值是一个新对象。

但是这个方式会有一个问题,因为他们的原型链指向的是同一个内存地址,所以如果父亲和儿子有相同的引用数据类型属性和方法,对其中的一个进行更改,那么另一个也会进行相应的更改,如果我们需要父亲儿子做不一样的事情,那么我们需要做一个小小的改动。就是利用一个介质或者说一个变量来对这个原型链进行一个保存,然后再将这个变量赋值给另一个原型链,那么这样他们就会互不干扰。

二、使用call或者apply改变this指向实现继承
function Father (name,age){
		this.name = name;
		this.age = age;
		this.introduce = function (){
			console.log('我是父亲我现在'+this.age+'岁');
		}
	}
	function Son (name,age){
		Father.call(this,name,age);//改变this指向
	}
	var father = new Father();
	var son = new Son('张三',48);//注意这边,如果父亲的方法中有参数的话,那么改变了this指向以后就变成了儿子的方法,那么就需要儿子接收参数,再通过call传递给父亲然后调用这个方法
	son.introduce();//儿子调用父亲的introduce方法

那么apply方法和call方法的不同就只是参数的不同,需要通过[ ]数组的形式来传递参数

function Son (name,age){
	Father.apply(this,[name,age]);
}

其实说到这里,还有一种方法bind,使用方法参照call,但是由于占内存和浏览器兼容性的问题,不常用。因此我们记住call和apply就完全够用了。
虽然这种方式解决了引用数据类型的关联改变,但是使用call或者apply这样的方式会破坏代码的复用,降低效率

三、组合方式实现继承(利用原型链加上call或者apply)

在上述中的一、二两种方式我们了解过后都有一些缺陷,那么我们现在使用组合办法解决这些缺陷,实现私有属性方法不可以更改,共有属性方法都可以访问,代码示例如下:

	function Father (name,age){
			this.name = name;
			this.age = age;
			this.list = [1,2,3]
		}
		Father.prototype.introduce = function (){
				console.log('我是父亲我现在'+this.age+'岁');
			}//在prototype中设置公有方法
		function Son (name,age){
			Father.call(this,name,age);//改变this指向
		}
		Son.prototype = new Father();//原型链继承
		Son.prototype.constructor = Son;//因为上一行代码实现原型链继承更改了构造函数,所以需要将父亲的改成自己的
		var son = new Son('张三',48);//注意这边,如果父亲的方法中有参数的话,那么改变了this指向以后就变成了儿子的方法,那么就需要儿子接收参数,再通过call传递给父亲然后调用这个方法
		son.introduce();//儿子调用父亲的introduce方法
		son.list.push(4);
		console.log(son.list);
		var son1 = new Son();
		console.log(son1.list);

结果如下:
在这里插入图片描述
这也是组合类型的优势,也是比较完善的继承,也是比较常用的方法。

四、ES6利用extends继承

如果学过java的朋友们那就会觉得很熟悉了,没错js中ES6的使用方式和java当中的继承相同,详细代码如下:

class Father{
		constructor (name,age){
			this.name = name;//属性
			this.age = age;
		}//构造函数
		introduce(){//方法
			console.log(this.name + '正在运动')
		}
	}
class Son extends Father{
	constructor(name,age) {
		super();//super 关键字用于访问父对象上的函数。当有了参数以后会访问父亲的constructor,并且返回当前this
		this.name = name;//属性
		this.age = age;
	}
}
var son = new Son('父亲',48);
// console.log(son);
son.introduce();//儿子调用父亲的introduce方法

那么关于js面向对象我们就先说到这里。
若有错误或缺陷请评论指出,将及时修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值