创建对象的几种模式

javascript中的面向对象


面向对象语言的的特性就是有类(class)的概念,通过类可以创建任意多个具有相同属性或方法的对象,然而 javascript 中没有类(class)的概念,所以它不是真正的面向对象

对象


由N组键值对组合起来的无序属性顺序的结合,其属性值可以是任意类型

//采用生成一个 Object 的实例来创建一个对象
var obj = new Object();
obj.name = "大毛";
obj.eat = function(){
    console.log("吃鱼")
}

//采用字面量方式创建新对象
var obj = {
    name: "大毛",
    eat: function(){
        console.log("吃鱼")
    }
}

以上我我们利用 Object 的构造函数和字面量方式创建了单个对象,但,这种模式创建出来的对象有个明显的缺陷:

同一个接口创建多个对象,会有很多重复代码,那如何解决呢?带着这个问题,我们继续探究...

工厂模式

利用函数封装,减少代码重复问题

function Cat(name,color){
    var o = new Object();
    o.name = name;
    o.color = color;
    return o;

}

//相当于调用函数 Cat
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("2毛","白色");

cat1.name //"大毛"
cat2.name //"2毛"

 缺陷:2个实例之间没有关联,并且不能反映出 2 个实例出自同一个原型对象

构造函数模式


所谓构造函数,就是普通函数,内部采用 this 变量,使用 new 运算符生成一个实例,建议函数名首字母大写

//猫的原型对象
function Cat(name,color){
    this.name = name;
    this.color = color
}
//生成2个实例
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

console.log(cat1.name); //"大毛"
console.log(cat2.name); //"2毛"

每一个实例,都将自动生成一个名为 constructor 的属性,指向他们的构造函数 

每个实例,都有一个 __proto__ ,这个是链接实例与构造函数的原型对象的而非是构造函数

function Cat(name,color){
    this.name = name;
    this.color = color
}
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

//实例的 constructor 实例的构造函数
cat1.constructor === Cat //true
cat2.constructor === Cat //true
cat1.constructor === cat2.constructor //true

cat1.__proto__ === Cat.prototype //true
cat1.__proto__ === Cat //false

instanceof 运算符,验证实例与原型之间的关系,返回 true/false  

function Cat(name,color){
    this.name = name;
    this.color = color
}
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

cat1 instanceof Cat //true
cat2 instanceof Cat //true

构造函数存在的缺陷:浪费内存

造成原因:当我们为构造函数添加不变的属性或方法时,生成实例时,会为每个实例都生成一模一样的属性或方法,因此,占用内存,也缺乏运行效率

function Cat(name,color){
    this.name = name;
    this.color = color;
    this.eat = function(){
        console.log("吃鱼");
    }
}
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

cat1.eat == cat2.eat // false

 因此,我们需要将构造函数中不变的属性或方法,在内存中只生成一次,然后所有的实例都指向这个内存地址,结果请看下面的原型链模式

原型链模式(prototype)


javascript规定,每次创建了函数,都会为函数添加一个 prototype 属性,指向函数的原型对象,默认情况下该原型的对象会自动有一个 constructor (构造函数) 属性,该属性指向构造函数,而原型对象中的所有属性和方法都被实例共享

我们将共同的属性或方法定义在prototype属性上,这样,所有的构造函数实例,都将直接继承原型链的属性或方法,减少了每次生成实例所产生的内存,同时有保证了,所有实例的这些属性或方法都执行同一个地址,提高运行效率

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.eat = function(){
    console.log("吃鱼");
}
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

//所有实例的 eat 都指向同一个内存地址,指向 prototype 对象
cat1.eat == cat2.eat //true

结合下图理解原型链模式

 原型链的验证方法


isPrototypeOf(),判断某个实例是否存在于某个 prototype 对象,返回 true/false

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.eat = function(){
    console.log("吃鱼");
}
var cat1 = new Cat("大毛","白色");
var cat2 = new Cat("2毛","黑色");

//使用 isPrototypeOf 判断实例是否是某个 prototype 对象
Cat.prototype.isPrototypeOf(cat1); //true

hasOwnProperty(),判断某个属性是否是本地属性,返回true/false

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.eat = function(){
    console.log("吃鱼");
}
Cat.prototype.type = "猫科";

var cat1 = new Cat("大毛","白色");

cat1.hasOwnProperty("name");//true
cat1.hasOwnProperty("type");//false

in,运算符,判断某个属性是否存在,不管是本地还是来自继承,返回 true/false

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.eat = function(){
    console.log("吃鱼");
}
Cat.prototype.type = "猫科";

var cat1 = new Cat("大毛","白色");

"name" in cat1 // true
"type" in cat1 // true

注意! in,还可遍历一个对象是所有属性

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值