javascript 中的面向对象实现 如何封装
面向对象的手法来封装javascript ,javascript是没有类的概念的.
所以今天谈到的封装,其实就是用javascript的函数来实现的.
1 2 3 4 |
var People{ name:’一介布衣’, age:’30' }; |
这就是javascript中的一个对象,里面封装了2个属性.
实例化一个对象的实例 people
1 2 |
var people=new People(); console.log(people.name,people.age); //一介布衣,30 |
如果我们需要在函数里返回一个对象,如下代码:
1 2 3 4 5 6 |
function CreatePeople(){ return { name:’一介布衣’, age:’30' }; } |
在代码中需要创建一个人的时候,我们需要调用 CreatePeople 即可,但是有一个问题,就是我们得到的都是同一个人 一介布衣,30岁.看来需要我们改造一个函数.
1 2 3 4 5 6 |
function CreatePeople(name,age){ return { name:name, age:age } } |
这看上去貌似好多了.我们实例化2个对象.
1 2 |
var p1=new CreatePeople(‘张三’,19); var p2=new CreatePeople(‘李四’,25); |
我们知道javascript从object 到其他全局类都有一个prototype对象指向原型链.
但是,p1,p2 俩个对象貌似没有一点关系,虽然被同一个函数创建,但是CreatePeople 每次返回一个全新的对象,看似 p1,p2关系不大.
如果你接触过面向对象语言的编程,这时应该想到了构造函数,但是上面的 CreatePeople 函数怎么看都不是一个构造函数,我们也可以用javascript的函数来生成一个构造函数.
1 2 3 4 |
function CreatePeople(name,age){ this.name=name; this.age=age; } |
this 和其他语言一样,也是一个指向实例的指针变量.
当用此构造函数创建对象的时候,this就指向新创建的对象,有一点需要记住,this取决调用函数作用域,而不是使用函数的作用域.
这样封装一下构造函数,生成的对象就比上面看上去顺眼多了.
2个属性指向了this实例指针,我们再来一个方法,去获取属性(也可以理解为私有变量)
1 2 3 4 5 6 7 |
function CreatePeople(name,age){ this.name=name; this.age=age; this.getName=function(){ return this.name; } } |
getName 方法很简单,就是返回对象中的 name 属性值.
实例化2个对象
1 2 |
var p1=new CreatePeople('张三',20); var p2=new CreatePeople('李四',21); |
1 2 |
console.log(p1.getName()) //张三 console.log(p2.getName()) //李四 |
这时感觉封装的高大上的感觉,其实我们没有发现,CreatePeople 构造函数中的 getName 函数干的活很简单,但是每次都在实例上创建一个这样的函数确实有点浪费内存了,我们看下面的代码.
1 |
console.log(p1.getName==p2.getName); //false |
返回false ,告诉我们 p1,p2 中的 getName 不是指向内存中的一个地址,我们为了节省内存,如何让CreatePeople 构建出来的对象,多有 getName 方法指向一个指针地址? 对,Object 的原型链上.
我们把这个方法定义在构造函数的原型链上,这样构造的新对象都会继承原型链上的这个方法,(具体的javascript中的继承我们单独开一篇博文来讨论)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function CreatePeople(name,age){ this.name=name; this.age=age; }
CreatePeople.prototype.getName=function(){ return this.name; }
var p1=new CreatePeople('张三',20); var p2=new CreatePeople('李四',21);
console.log(p1.getName==p2.getName); //true |
可以看到p1 和 p2 对象都继承来自 CreatePeople 原型上的 getName 方法,而且所有对象的此方法指针都指向了一个地址.
这样,我们封装的目的就达到了.