javascript面向对象编程

对象的定义:一组属性的集合。

属性

一个对象中的某一项(键值对)称为属性。属性名是字符串,属性值可以是任何javascript值,当属性值是一个函数的时候,我们称之为方法。

创建对象的方法

1.字面量法

var obj1={
	name:'a',
	method:function(){
		console.log(this.a);
	}
}

2.构造函数法

var obj2=function(){
	this.name='a';           
	this.method=function(){  
		console.log(this.name);
	}
}

3.Object

var o1=new Object();
var o2=Object.create({});
var o3=Object.create(Object.prototype);
/*如果想要生成一个不继承任何属性(比如没有toString和valueOf方法)的对象,可以将Object.create的参数设为null。*/
var o4=Object.create(null);

如何给对象添加/修改/删除属性

不管用以上哪种方法创建出了一个对象,都能用 . 去添加属性,用 [] 也可以添加属性。点运算符与方括号的区别在于方括号可以动态计算属性键名。举个例子:

var obj={
	name1:'a',
	name2:'b',
	name3:'c'
}
for(var i=1;i<4;i++){
	console.log(obj['name'+i]);
}

使用delete运算符去删除对象属性。举个例子:

var obj={
	name1:'a',
	name2:'b'
}
delete obj.name1
console.log(obj.name1);//undefined

在javascript中有两种面向对象的机制

一种是单一对象,一种是构造函数。

单一对象的作用类似于其他语言的映射表/字典。仅仅只是把一组组的属性给罗列出来。等待人们去使用这些属性和方法。

构造函数就相当有意思了,我们知道js是一门弱类型语言,很多东西比如类它都没有。构造函数就是用来模拟其他语言的类这个概念。举个例子让我们看看它是如何模拟的。

var obj2=function(){
	var age=12;              //私有属性
	function pri_method(){}; //私有方法
	this.name='a';           //公有属性
	this.method=function(){  //公有方法
		console.log(this.name);
	}
}
obj2.prototype.sex='boy';   //公有属性
var o1=new obj2();

解释一下,由于js的函数级作用域,使得声明在函数内部的变量与方法外界访问不到,通过此特性可创建私有变量与私有方法。构造函数创建实例是通过new运算符创建的,其中new有一个作用是给this赋值,使this指向实例对象。所以绑定在this上面的属性就会传递给实例,所以他们是公有属性。

所以说构造函数就是用来实现类的功能,用来创建实例的。下面就来说说构造函数。

肤浅地来看,构造函数有两个明显的特征,一是身为一个函数它没有return,二是属性和方法被绑定在this上。但加上return,只要返回的不是一个对象,那就可以照常构造实例,this依旧会指向new前面的变量。但是一旦返回的是对象,那么this将不再指向new前的变量。

new 命令的原理

1.创建一个空对象,作为将要返回的对象实例。
2.将这个空对象的原型,指向构造函数的prototype属性。
3.将这个空对象赋值给函数内部的this关键字。
4.开始执行构造函数内部的代码。

构造函数主要和继承有关。如果你对原型不是很了解,请先看我的另一篇博客 prototype 。是时候来聊聊继承了。

继承

1.类氏继承

举个例子:

function Parent(){
	this.name='abc';
	this.cars=['BMW','Ferrari','ofo'];
}
Parent.prototype.getName=function(){
	console.log(this.name);
}
function Children(){
	this.age=12;
}
Children.prototype=new Parent();
var son=new Children();
var daughter=new Children();
console.log(son.name);//abc
son.getName()         //abc
daughter.cars.push('bike');
console.log(son.cars);//[ 'BMW', 'Ferrari', 'ofo', 'bike' ]

类氏继承的原理很简单,利用new命令符的原理,把parent中绑定在this上的属性放进children.prototype对象中,然后children.prototype.__proto__指向parent.prototype,这样children又能有parent.prototype中的属性,继承完成。

相当于Children.prototype是Parent的实例。

这种继承方式有个缺点。如果Parent的this上的属性是引用类型,那么一个子类的实例改变了这个属性,所有实例的这个属性都会改变。


2.构造函数继承

function Parent(name){
	this.name=name;
	this.cars=['BMW','Ferrari','ofo'];
}
Parent.prototype.getName=function(){
	console.log(this.name);
}
function Children(name){
	Parent.call(this,name);
}
var son=new Children('Bob');
var daughter=new Children('Alice');
console.log(son.name);//Bob
console.log(daughter.name);//Alice
daughter.cars.push('bike');
console.log(son.cars);//[ 'BMW', 'Ferrari', 'ofo']

构造函数继承,弥补了类氏继承的不足。

这段代码的精髓在于

Parent.call(this,name);

call可以改变函数执行的作用域,这里传入的this,在后面创建实例的时候是指向实例的,所以执行Parent函数时,绑定在this上的所有属性,最终都会被绑定到实例上。以此来实现实例继承父类属性。

但这种类型的继承没有涉及到原型prototype,所以父类的原型不会被子类继承,父类prototype中的属性不会被子类拥有。


3.组合继承

function Parent(name){
	this.name=name;
	this.cars=['BMW','Ferrari','ofo'];
}
Parent.prototype.getName=function(){
	console.log(this.name);
}
function Children(name){
	Parent.call(this,name);
}
Children.prototype=new Parent();
var son=new Children('Bob');
var daughter=new Children('Alice');
daughter.cars.push('bike');
console.log(son.cars);//[ 'BMW', 'Ferrari', 'ofo' ]
son.getName();        //Bob
daughter.getName();   //Alice

只需要在构造函数继承的基础上,加一句 Children.prototype=new Parent() ,建立父类原型与子类原型的联系即可。

这种继承的优点是,实例更改从父类继承的引用类型属性,不会影响其他实例,且又能共享从父类继承的prototype。

但是父类的构造函数调用了两遍,Parent.call调用了一遍,new Parent()又调用了一遍。


4.原型式继承

这个和类氏继承有点像,举个例子:

function inheritObject(o){
	function F(){};
	F.prototype=o;
	return new F();
}
var Cars={
	name:'1车厂',
	cars:['BMW','Ferrari','ofo']
};
var car1=inheritObject(Cars);
var car2=inheritObject(Cars);
car1.name='2车厂';
car1.cars.push('Maybach');
console.log(car2.name);//1车厂
console.log(car2.cars);//[ 'BMW', 'Ferrari', 'ofo', 'Maybach' ]
注意传进inheritObject的对象,应该是字面量的形式。其实inheritObject就是一个实例工厂,创建出的所有实例对象有一个共同的特点,它们的原型模板是相同的,注意每个实例的原型是单独的,只不过原型中的引用类型的值是共享的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值