javascript基础--对象(Object)封装

javascript基础--对象(Object)封装

2017年02月03日 16:21:54 阅读数:1970 标签: javascript对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/csdn_kingboss/article/details/54847780

引言

说到对象,我想到一个成语叫作谈虎色变,对象应该说是javascript中最难得一部分,原因呢,首先,js作为函数式编程语言,对象的实现方式跟java,c,c++等面向对象设计语言不一样;其次js面向对象编程属于高级程序员应该掌握的,对于初学者来讲,没有实践基础,凭空理解更是难上加难。不过不用担心,我也不怎么会,我们就一起来探讨一下吧。

1.对象封装

我们举个例子,大千世界,人心难测。每个人都是独立的,有自己的思维,性别,年龄,会跑,会跳等等,人就是一个单位,一个整体,然后人与人之间才会有血缘关系,社会关系。试想,一个人都不完整,还谈什么其他东西呢?所以我们的首先任务就是“造人”,造人的方式的有很多种,当然肯定不是你想的那种,哈哈!好,接下来,开始造人吧!

2.封装模式一:工厂模式

工厂模式的原理:在函数内部创建object对象,对象属性由参数指定,方法也挂在object对象上,最后返回这个object对象。相当于Person函数是一个造人工厂,一下子造了Tom,Linda两个人。但是缺点是不知道这两个人什么类型的,你会说都是object啊,对啊,你回答这个答案就像我问你你现在在哪?你说你在地球上一样的道理。我们应该知道,js里所有事物都是object类型,所以为了搞明白这两个人具体的类型,我们另有他法,那就是构造函数模式。

function Person(name,sex){
    var o = new Object();
    o.name =  name;
    o.sex = sex;
    o.say = function(){
        console.log(this.name + ' is '+ this.sex)
    };
    return o;
}
var Tom = Person('Tom','male');
var Linda = Person('Linda','female');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.封装模式二:构造函数模式

构造函数模式相比工厂函数就是知道Tom和Linda这两个人是Person类型,原理是new关键字默认执行了以下操作: 
1.创建一个全新的对象 
2.这个对象会被执行[[prototype]]连接原型 
3.函数调用中的this会绑定到新对象 
4.如果函数没有返回其他对象,那么new 构造就会自动返回这个新对象 
注意:这里我特意加粗这句话,因为文末讲的寄生构函数模式的理解需要仰仗这句话。先透个底,如果函数像工厂函数那样返回了对象,那么new关键词也就不会执行默认操作。

function Person(name,sex){
    this.name = name;
    this.sex = sex;
    this.say = function(){
        console.log(this.name + ' is '+ this.sex);
    }
}
var Tom = new Person('Tom','male');
var Linda = new Person('Linda','female');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上述的原型链图示为: 
这里写图片描述

Person.prototype指向原型对象,而原型对象的constructor属性指向构造函数Person,Tom和Linda实例继承了原型对象的constructor属性,所以有下面的等式

console.log(Tom.constructor === Person.prototype.constructor && Tom.constructor === Person);//ture
console.log(Linda.constructor === Person.prototype.constructor && Linda.constructor === Person);//ture
  • 1
  • 2

javascript还提供了instanceof,验证实例与构造函数的关系

console.log(Tom instanceof Person);//true
console.log(Linda instanceof Person);//true
  • 1
  • 2

4.封装模式三:原型模式

构造函数有个弊端,就是每一次new一个对象的时候,其实都创建了各自的属性和方法,这些属性和方法是重复的,完全没必要嘛,代码量多,又浪费内存。原型模式解决了这个问题,将公用方法和不变的属性挂在原型对象上。

//构造函数模式new的实例,相同的属性和方法是不一致的,验证一下
console.log(Tom.name === Linda.name);//false
console.log(Tom.sex === Linda.sex);//false
console.log(Tom.say === Linda.say);//false
//不对就对了,下面是原型模式
function Person(){}
Person.prototype.name = 'Tom';
Person.prototype.sex = 'male';
Person.prototype.say = function(){
    console.log(this.name + ' is '+ this.sex);
};
var Tom = new Person();
var Linda = new Person();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

原型链图示为: 
这里写图片描述

实例属性或方法的访问过程是一次搜索过程: 
1.首先从对象实例本身开始,如果找到属性就直接返回该属性值; 
2.如果实例本身不存在要查找属性,就继续搜索指针指向的原型对象,在其中查找给定名字的属性,如果有就返回; 
基于以上分析,原型模式创建的对象实例,其属性是共享原型对象的;但也可以自己实例中再进行定义,在查找时,就不从原型对象获取,而是根据搜索原则,得到本实例的返回;简单来说,就是实例中属性会屏蔽原型对象中的属性;

接下来看一下这些属性和方法相等吗?

console.log(Tom.name === Linda.name);//true
console.log(Tom.sex === Linda.sex);//true
console.log(Tom.say === Linda.say);//true
  • 1
  • 2
  • 3

javascript提供一些验证实例和原型对象关系的方法

//isPrototypeOf用来判断,某个原型对象和某个实例之间的关系
console.log(Person.prototype.isPrototypeOf(Tom)); //true
console.log(Person.prototype.isPrototypeOf(Linda)); //true
//hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性
console.log(Tom.hasOwnProperty("name")); // false
console.log(Linda.hasOwnProperty("name")); // false
//in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性
console.log("name" in Tom); // true
console.log("name" in Linda); // true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5.封装模式四:组合构造函数及原型模式

简称组合模式,构造函数实例好比私有制,原型模式实例好比公有制,那么组合模式就是以公有制为核心,私有制并行的模式,佩服我历史学得真好!所以自己的属性就不要挂在原型对象上,只有共有属性和方法才挂在上面。

function Person(name,sex){
    this.name = name;
    this.sex = sex;
}
Person.prototype = {
    //原型字面量方式会将对象的constructor变为Object,此外强制指回Person
    constructor: Person,
    say: function(){
        console.log(this.name + ' is '+ this.sex);  
    }
}
var Tom = new Person('Tom','male');
var Linda = new Person('Linda','female');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

原型链示图:

这里写图片描述

做些测试吧!

console.log(Tom.name);//Tom
console.log(Linda.name);//Linda
console.log(Tom.say === Linda.say);//true 
  • 1
  • 2
  • 3

6.封装模式五:动态原型模式

组合模式私有属性和共有属性及方法是分离的,如果能够放在一个构造函数里,那就真的和对象相差无几了。

function Person(name,sex){
    this.name = name;
    this.sex = sex;
    if(typeof this.say != 'function'){
        Person.prototype = {
            constructor: Person,
            say: function(){
                console.log(this.name + ' is '+ this.sex);
            }
        }
    }
}
var Tom = new Person('Tom','male');
var Linda = new Person('Linda','female');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

来验证一下吧!

console.log(Tom.name);//Tom
console.log(Linda.name);//Linda
//===>想想为什么第一个Tom.say返回undefined?我似懂非懂
Tom.say;//undefined
Linda.say;//function 
  • 1
  • 2
  • 3
  • 4
  • 5

7.封装模式六:寄生构造函数模式

还记得讲构造函数模式的时候,new的实质吗?温习一下: 
new的实质是执行了以下操作 
1.创建一个全新的对象 
2.这个对象会被执行[[prototype]]连接原型 
3.函数调用中的this会绑定到新对象 
4.如果函数没有返回其他对象,那么new 构造就会自动返回这个默认对象 
注意:如果返回了其他对象,那么new关键词也就不会执行默认操作。

现在有个疑问:以上以new创建实例的模式都没有返回新对象,而是依靠new的默认操作创建的对象实例。但是,but,but,new默认返回的对象是object类型,如果我现在要返回array或者其他对象,new就不能再执行其默认操作了,所以就要用return语句重写构造函数,返回期望的对象类型。

function SpecialArray(){
    var values = new Array();
    values.push.apply(values, arguments);
    values.toPipedString = function(){
        return this.join("|"); 
    };
    return values; 
}
var a = new SpecialArray(2,6,8,9,4);
a.toPipedString();//2|6|8|9|4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上面是网上随便找的一段关于创建数组对象的例子,我们还是改写我们的例子

function Person(name,sex){
    var o = new Object();
    o.name =  name;
    o.sex = sex;
    o.say = function(){
        console.log(this.name + ' is '+ this.sex)
    };
    return o;
}
//与工厂模式的区别就是调用的时候加上了new关键字,工厂模式直接调用函数
var Tom = new Person('Tom','male');
var Linda = new Person('Linda','female');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

那么就有人问了,这寄生构造函数模式又产生什么结果呢?其实答案和工厂模式输出结果一模一样。那有了工厂模式了,寄生构造模式是不是多余的呢?借用高程书上的原话: 
书上原话:除了使用new操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样的。构造函数在不返回值的情况下。默认会返回新对象实例。而通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值。

结束语

对象涉及封装和继承,继承放在后一片文章去讲。弄了这么一通,对象封装也就6个模式,寄生构造函数模式跟工厂模式没有什么大区别,而且我们经常用的是组合模式和动态原型模式。所以实践看起来是要比学习单纯许多。哈哈

猜你喜欢

转载自blog.csdn.net/wang__qin/article/details/82017336