创建对象的几种方式
- 工厂模式
- 构造函数模式
- 原型模式
- 混合构造函数和原型模式
- 动态原型模式
- 寄生构造函数模式
- 委托构造函数模式
js创建对象就是事已内置对象或各种自定义对象,还可以用JSON.
- 对象字面量的方式
Person = {
firstName:"jin",
lastName:"xiaodong",
age:18,
eyecolor:"black"
};
- 用function来模拟无参的构造函数
function Person(){}
//定义一个function,如果使用new实例化,该function可以看作一个Class
var person = new Person();
person.name = 'jin';
person.age=18;
person.work =function(){
alert(person.name + 'hello...');
}
person.work();
- 用function来模拟有参构造函数来实现
function Pet(name,age,hobby){
this.name = name;
this.age = age;
this.hobby = hobby;
this.eat = function(){
alert(this.name + "is a chengxiyan ...")
}
}
var maidou = new Pet("麦兜",12,"coding");
maidou.eat()
- 用工厂方式创建(内置对象)
var wcDog = new Object();
wcDog.name = "旺财";
wcDog.age = 11;
wcDog.work = function(){
alert(wcDog.name+'wangwang ...')
}
wcDog.work()
- 用原型的方式创建
function Dog(){}
Dog.prototype.name = "wangcai";
Dog.prototype.eat = function(){
alert(this.name + "eat...")
}
var wangcai = new Dog();
wangcai.eat();
- 用混合方式创建
function Car(name,price){
this.name = name;
this.price =price;
}
Car.prototype.sell=function(){
alert(this.name +this.price)
}
var camry = new Car('carmy',12222);
carmy.sell()
实现单例模式
1.最简单的对象字面量
var singLeton = {
attr:1,
method:function(){
return this.attr;
}
}
var t1 = singLeton;
var t2 = singLeton;
t1 === t2十分简单,不足之处在于没有什么封装性,所有的属性方法都是暴露的.
对于一些需要使用私有变量的情况心有余而力不足.
2.构造函数内部判断
将对是否已经存在该类的实例的判断放入构造函数内部.
function Construct(){
//确保只有单例
if(Construct.unique !== undefined){
return Construct.unique;
}
this.name = name;
this.age = '12';
Construct.unique = this;
}
vat t1 = new Construct();
var t2 = new Construct();
t1===t2,该方式没有安全性,一旦在外部修改了Construct的unique属性,单例模式就被破坏了
3.闭包方式
var single = (function(){
var unique;
function Construct(){
//确保只有单例
if(Construct.unique !== undefined){
return Construct.unique;
}
this.name = name;
this.age = '12';
Construct.unique = this;
}
unique = new Construct()
return unique;
})()
与对象字面量方式类似,不过相对而言更安全咦喜,也不绝对安全.
继承的实现
- 使用对象冒充实现继承
可以实现多继承;
继承原理:让父类的构造函数成为子类的方法,然后调用该子类的方法.通过this关键字给所有的方法和属性赋值.
function Parent(firstName){
this.fname = firstName;
this.age =18;
this.sayAge = function(){
console(this.age)
}
}
function Child(firstName){
this.parent = Parent;
this.parent(firstName);
delete this.parent;
this.saySomeThing = function(){
console.log(this.fname);
this.sayAge();
}
}
var mychild = new Child('xd');
mychild.saySomeThing()
- 采用call方法改变函数上下文实现继承
该方式不能继承原型链,
实现原理:改变函数内部上下文this,使他指向传入函数的具体对象
function Parent(firstName){
this.fname = firstName;
this.age =18;
this.sayAge = function(){
console(this.age)
}
}
function Child(firstName){
this.saySomeThing = function(){
console.log(this.fname);
this.sayAge();
}
this.getName = function(){
return firstName;
}
}
var child = new Child('xd')
Parent.call(child,child.getName())
child.saySomeThing()
- 采用apply方式改变函数上下文实现继承
不能继承原型链
实现原理:改变函数内部的函数上下文this,使他指向传入函数的具体对象
function Parent(firstName){
this.fname = firstName;
this.age =18;
this.sayAge = function(){
console(this.age)
}
}
function Child(firstName){
this.saySomeThing = function(){
console.log(this.fname);
this.sayAge();
}
this.getName = function(){
return firstName;
}
}
var child = new Child('xd')
Parent.apply(child,[child.getName()])
child.saySomeThing()
- 采用yuanxl的方式实现继承
实现原理:使子类原型对象指向父类的实例以实现继承,即重写类的原型,弊端使不能直接实现多继承
function Parent(){
this.sayAge = function(){
console(this.age)
}
}
function Child(firstName){
this.fname = firstName;
this.age =18;
this.saySomeThing = function(){
console.log(this.fname);
this.sayAge();
}
}
Child.prototype = new Parent();
var child = new Child('xd')
child.saySomeThing()
- 采用混合模式实现继承
function Parent(){
this.sayAge = function(){
console(this.age)
}
}
Parent.prototype.sayParent = function(){
console.log('sayParent');
}
function Child(firstName){
Parent.call(this)
this.fname = firstName;
this.age =18;
this.saySomeThing = function(){
console.log(this.fname);
this.sayAge();
}
}
Child.prototype = new Parent();
var child = new Child('xd')
child.saySomeThing()
child.sayParent();
如何实现面向对象和继承机制
通过Object构造函数创建对象
var school = new Object();
school.name = "aaaa";
school.teacher = "jxd";
school.sayName = function(){
console.log(this.name);
}
school.sayName();
对象字面量创建对象,单例模式
var school = {
name:"aaa",
teacher:"jxd",
sayName: function(){
console.log(this.name);
}
};
school.sayName();
虽然Object构造函数和对象字面量都可以创造单个对象,但这些方式有缺点:使用同一个接口创建很多对象,会产生大量的重复的代码.
工厂模式
var creatSchool = function(name.teacher){
var o = new Object();
o.name = name;
o.teacher=teacher;
o.sayName = function(){
console.log(this.name)
}
return o;
}
var school = creatSchool("aaa","jxd");
school.sayName();
工厂模式解决了创建多个相似对象的问题,但是没有解决对象的识别问题,即怎么知道一个对象类型.
构造函数模式
var School = function(name,teacher){
this.name = name;
this.teacher=teacher;
this.sayName = function(){
console.log(this.name)
}
}
var school = new School("aaa","jxd");
school.sayName();
使用构造函数的主要问题使每个方法都要在每个实例上重新创建一遍
原型模式
每个函数都有一个prortotype属性,这个属性是一个指针,指向一个对象,而这个对象的用途使所有实例共享属性和方法.
var School = function(name,teacher){
this.prototype.name = "aaa";
this.prototype.teacher="jxd";
this.prototype.sayName = function(){
console.log(this.name)
}
}
var school1 = new School();
var school2 = new School();
console.log(school.sayName === school2.sayName)//true
school.sayName();
school1.sayName,school2.sayName指向内存中同一地址.
组合使用构造函数和原型模式
var School = function(name,teacher){
this.name = name;
this.teacher=teacher;
this.domain = 'taobao.com';
this.students =['xd1','xd2'];
}
School.prototype = {
constructor:School,
sayName: function(){
console.log(this.name)
}
}
var school1 = new School("aaa","jxd");
var school2 = new School("aaa","jxd");
school1.students.push('xd3');
console.log(school1.students)//['xd1','xd2','xd3']
console.log(school2.students)//['xd1','xd2']
console.log(school1.students === school2.students)//false
console.log(school1.sayName === school2.sayName)//true
注意
- 实例属性都是在构造函数中定义的,而所有的实例共享的属性和方法都是在原型中定义的
- 这种构造函数与原型混合的模式,是目前使用最广泛的,认同度最高的一种创建自定义的方法.
继承机制是面向对象语言的三大特性:继承,封装,多态.之一,许多面向对象语言都支持两种继承方式:接口继承,实现继承.