深入解读JavaScript面向对象编程实践
Javascript是一门解释性脚本语言,同时它也是一门面向对象编程语言,但是它跟Java,c++等又不一样,因为它没有类(class),那么我们要如何把属性(
property)和方法(method)封装成一个对象,从原型对象实例化出来一对象呢?
一、对象类的创建
在JavaScript中,我们通常可以使用构造函数来创建特定类型的对象。诸如Object和Array这样的原生构造函数,在运行时会自动出现在执行环境中。 此外,我们也可以创建自定义的构造函数。
1 function Man(name, age, job) { 2 this.name = name; 3 this.age = age; 4 this.job = job; 5 } 6 var man1 = new Person('Weiwei', 27, 'Student'); 7 var man2 = new Person('Lily', 25, 'Doctor');
按照惯例,构造函数始终都应该以一个大写字母开头(和Java中定义的类一样),普通函数则小写字母开头。 要创建Person
的新实例,必须使用new
操作符。
这样调用构造函数一般经过一下四个步骤:
-
创建一个新对象(实例)
-
将构造函数的作用域赋给新对象(也就是重设了
this
的指向,this
就指向了这个新对象) -
执行构造函数中的代码(为这个新对象添加属性)
-
返回新对象
在上面的例子中,person1,person2 会默认都有一个constructor 属性,该属性指向它们的构造函数Man,即为:
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
二、prototype 原型问题
来看这段代码:
1 function Man(name,age,job) { 2 this.name = name ; 3 this.age = age; 4 this.job = job; 5 this.type = "person" ; 6 this.action =function(){ 7 alert('walk'); 8 } 9 } 10 11 man1 = new Man("wei","20","student"); 12 console.log(man1.type); 13 //person
这样子看起来好像没什么问题,但其实每次实例化,实例的 type 和 action 都是一样的, 这样就造成多次重复,占用了内存,实际上javascript规定,每个构造函数都有一个 prototype 属性,指向另一个对象,这个对象所有属性和方法,都会被实例化继承。
也就是说,我们可以把那些不会变得属性和方法全部定义在 prototype 对象上。
1 function Man(name,age,job){ 2 this.name = name; 3 this.age = age; 4 this.job = job; 5 } 6 Man.prototype.type = "person"; 7 Cat.prototype.action = function(){alert("walk")};
然后生成实例;
1 man1 =new Man("wei","20","student");
2 alert(man1.type); //person
上图展示了Man
构造函数、Man
的原型对象以及Man
现有的实例之间的关系。
Person.prototype
指向了原型对象Person.prototype.constructor
又指回了Person
构造函数Person
的实例man1一个内部属性(通常为__proto__
),man1.__proto__
指向了原型对象
三、 Prototype模式的验证方法
为了配合 prototype 属性,javascript 定义了一些方法,帮助我们使用它。
3.1 isPrototypeOf()
这个方法用来判断,某个proptotype
对象和某个实例之间的关系。
1 alert(Man.prototype.isPrototypeOf(man1)); 2 // true;
3.2 hasOwnProperty()
每个实例对象都有一个 hasOwnProperty ()方法用于判断某一属性是来自本地属性,还是继承自prototype对象,若来自本地返回 true,否则返回 false;
1 man1.hasOwnProperty("name"); 2 man1.hasOwnProperty("type"); 3 //true 4 //false
3.3 in 运算符
同样 可以用 for in 来遍历对象
1 for(var prop in man1){ 2 console.log("man1["+prop+"] = "+man1[prop]); 3 } 4 //man1[name] = ben 5 // man1[age] = 20 6 // man1[job] = student 7 //man1[type] = person 8 // man1[action] = function (){alert("walk")}
同时 in 也可以用来检测属性是否在对象内,不管是本地对象,还是prototype 的属性
1 console.log("eat" in man1); 2 //false 3 undefined 4 console.log("type" in man1); 5 6 // true 7 8 console.log("name" in man1); 9 10 //true