这篇文章主要为大家详细介绍了Javascript的面向对象入门实例(三),具有一定的参考价值,可以用来参考一下。
在Javascript中,虽然借助原型链就可以实现继承,但这里面还是有很多细节问题的要处理的。分析并解决这些问题后,就可以把创建类的过程写成一个通用函数了。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A() { }
var a = new A();
a.constructor; // A
确切地说,constructor属性是位于构造函数的prototype上。下面的代码可以证实这一规则:
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A() { }
var a = new A();
console.log(a.constructor); // A
delete A.prototype.constructor; // 删除原型上的constructor属性
console.log(a.constructor); // Object
由于删除了A.prototype下的constructor属性,所以访问a.constructor的时候,在原型链中的查找就得查到Object.prototype上去,而Object.prototype.constructor自然就是Object。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A() { }
function B() { }
B.prototype = new A();
var a = new A();
a.constructor; // A
var b = new B();
b.constructor; // A
可见,b的constructor应为B,但却成了A。原因是:b.constructor即B.prototype.constructor,而此时B.prototype是一个A对象,A对象的constructor即A.prototype.constructor,而A.prototype.constructor正是A。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A() { }
function B() { }
B.prototype = new A();
B.prototype.constructor = B; // important
var a = new A();
a.constructor; // A
var b = new B();
b.constructor; // B
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
var arr = new Array();
arr instanceof Array; // true
arr instanceof Object; // true
由于Array.prototype和Object.prototype都在arr的原型链中,所以上面的测试结果均为true。另外还要注意,instanceof的检测只跟原型链有关,跟constructor属性没有任何关系。所以,基于原型链的继承不会影响到instanceof的检测。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A(data) {
this.name = data.name;
}
A.prototype.sayName = function() {
console.log(this.name);
};
function B() { }
B.prototype = new A();
B.prototype.constructor = B;
var b = new B();
这段代码运行的时候会产生异常:
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A(data) {
this.name = data.name;
}
A.prototype.sayName = function() {
console.log(this.name);
};
function B() { }
B.prototype = new A({ });
B.prototype.constructor = B;
var b = new B();
b.sayName(); // undefined
然而,实际情况远没有这么简单。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A(data) {
this.name = data.name;
}
A.prototype.sayName = function() {
console.log(this.name);
};
function B() { }
function Empty() { }
Empty.prototype = A.prototype; // important
B.prototype = new Empty();
B.prototype.constructor = B;
var b = new B();
b.sayName(); // undefined
Empty即为该空函数,它的prototype被更改为A.prototype,即Empty与A共享同一个prototype。因此,在忽略构造函数内部逻辑的前提下,把B.prototype设成Empty的实例跟设成A的实例效果是一样的。但因为Empty内部没有逻辑,所以new Empty()肯定不会产生异常。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A(data) {
this.name = data.name;
}
A.prototype.sayName = function() {
console.log(this.name);
};
function B() { }
B.prototype = Object.create(A.prototype); // important
B.prototype.constructor = B;
var b = new B();
b.sayName(); // undefined
其二,很多时候我们需要把子类构造函数的参数传给父类构造函数。比如说达到这样的效果:
var b = new B({ name: 'b1' });
b.name; // 'b1'
这就需要在子类构造函数中调用父类构造函数:
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function A(data) {
this.name = data.name;
}
function B() {
A.apply(this, arguments); //important
}
function Temp() { }
Temp.prototype = A.prototype;
B.prototype = new Temp();
B.prototype.constructor = B;
var b = new B({ name: 'b1' });
console.log(b.name);
通过A.apply(this, arguments)就可以确保操作的对象为当前对象(this),且把所有参数(arguments)传到A。
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
function createClass(constructor, methods, Parent) {
var $Class = function() {
// 有父类的时候,需要调用父类构造函数
if (Parent) {
Parent.apply(this, arguments);
}
constructor.apply(this, arguments);
};
if (Parent) {
// 处理原型链
var $Parent = function() { };
$Parent.prototype = Parent.prototype;
$Class.prototype = new $Parent();
// 重设constructor
$Class.prototype.constructor = $Class;
}
if (methods) {
// 复制方法到原型
for (var m in methods) {
if ( methods.hasOwnProperty(m) ) {
$Class.prototype[m] = methods[m];
}
}
}
return $Class;
}
在这个函数的基础上,把计算周长的问题解决掉:
/**
* 面向对象入门实例
*
* @param
* @arrange (512.笔记) www.q1010.com
**/
// 形状类
var Shape = createClass(function() {
this.setName('形状');
}, {
getName: function() { return this._name; },
setName: function(name) { this._name = name; },
perimeter: function() { }
});
// 矩形类
var Rectangle = createClass(function() {
this.setLength(0);
this.setWidth(0);
this.setName('矩形');
}, {
setLength: function(length) {
if (length < 0) {
throw new Error('...');
}
this.__length = length;
},
getLength: function() { return this.__length; },
setWidth: function(width) {
if (width < 0) {
throw new Error('...');
}
this.__width = width;
},
getWidth: function() { return this.__width; },
perimeter: function() {
return (this.__length + this.__width) * 2;
}
}, Shape);
// 正方形类
var Square = createClass(function() {
this.setLength(0);
this.setName('正方形');
}, {
setLength: function(length) {
if (length < 0) {
throw new Error('...');
}
this.__length = length;
},
getLength: function() { return this.__length; },
perimeter: function() {
return this.__length * 4;
}
}, Shape);
// 圆形
var Circle = createClass(function() {
this.setRadius(0);
this.setName('圆形');
}, {
setRadius: function(radius) {
if (radius < 0) {
throw new Error('...');
}
this.__radius = radius;
},
getRadius: function() { return this.__radius; },
perimeter: function() {
return 2 * Math.PI * this.__radius;
}
}, Shape);
function computePerimeter(shape) {
console.log( shape.getName() + '的周长是' + shape.perimeter() );
}
var rectangle = new Rectangle();
rectangle.setWidth(10);
rectangle.setLength(20);
computePerimeter(rectangle);
var square = new Square();
square.setLength(10);
computePerimeter(square);
var circle = new Circle();
circle.setRadius(10);
computePerimeter(circle);
本文来自:http://www.q1010.com/174/1650-0.html
注:关于Javascript的面向对象入门实例(三)的内容就先介绍到这里,更多相关文章的可以留意四海网的其他信息。
关键词:面向对象
四海网收集整理一些常用的php代码,JS代码,数据库mysql等技术文章。