面向对象
<script type="text/javascript">
// 面向对象:就是一种编程思想,只关注其功能,不关注其内部细节
// 面向对象特点:
//1.封装 :不考虑内部实现,只考虑功能
//2.继承 :从已有的对象上,继承出新的对象
//3.多态 :不同的操作,产生不同的结果
//JS的面向对象
//JS是基于对象的,它不是面向对象
//对象组成
//1.属性 :变量
//2.方法 :函数
var ary = [1, 2, 3];
//alert(typeof(ary)); //object
//数组的属性 ary.length
//数组的对象的方法 ary.push()
var ary2 = [4, 5, 6];
//属于一个对象的变量叫属性
//属于一个对象的函数叫方法
//创建空对象
var obj = new Object();
obj.name = "邹振洲";
obj.sex = "boy";
obj.showName = function(){
alert(this.name);
}
obj.showName();
var obj2 = new Object();
obj2.name = "小风儿";
obj2.sex = "boy";
obj2.showName = function(){
alert(this.name);
}
obj2.showName();
</script>
工厂方式
<script type="text/javascript">
//工厂方式
function CreatePerson(name, sex){
//1.原料
var obj = new Object();
//2.加工
obj.name = name;
obj.sex = sex;
obj.showName = function(){
alert(this.name);
};
obj.showSex = function(){
alert(this.sex);
}
//3.出厂
return obj;
}
var p1 = CreatePerson("阿波罗", "boy");
var p2 = CreatePerson("asdf", "boy");
p1.showName();
p2.showName();
alert(p1.showName == p2.showName);//false
//工厂方式的缺点:
//1.每一个对象都有一套自己的方法,浪费资源
//2.没有new
</script>
new
<script type="text/javascript">
//构造函数:用来创建对象的函数
function CreatePerson(name, sex){
//var this = new Object(); //下面使用new 本行系统默认写出
this.name = name;
this.sex = sex;
this.showName = function(){
alert(this.name);
};
this.showSex = function(){
alert(this.sex);
}
//return this; //下面使用new 本行系统默认写出
}
//new过程叫做实例化
//p1实例(实例化的对象)
var p1 = new CreatePerson("小风儿", "boy");
p1.showName();
</script>
给数组添加方法
<script type="text/javascript">
//var ary1 = new Array(1, 2, 3);
//数组是系统对象
//扩展系统对象的属性和方法
var ary1 = [1, 2, 3];
var ary2 = [4, 5, 6];
ary1.sum = function(){
var s = 0;
for(var i = 0; i < this.length; i++){
s += this[i];
}
return s;
}
alert(ary1.sum());
ary1.push(10);
alert(ary1.sum());
</script>
prototype
<script type="text/javascript">
//给Array原型加方法
Array.prototype.sum = function(){
var s = 0;
//this 代表实例化的对象 ary1
for(var i = 0; i < this.length; i++){
s += this[i];
}
console.log(this);
return s;
}
var ary1 = [1, 2, 3];
var ary2 = [4, 5, 6];
alert(ary1.sum());
alert(ary2.sum());
alert(ary1.sum == ary2.sum);
</script>
混合法
<script type="text/javascript">
//混合法创建对象
function CreatePerson(name, sex) {
//构造函数里添加属性
this.name = name;
this.sex = sex;
}
//原型上添加方法
CreatePerson.prototype.showName = function() {
alert(this.name);
};
CreatePerson.prototype.showSex = function() {
alert(this.sex);
}
var p1 = new CreatePerson("小风儿", "boy");
var p2 = new CreatePerson("小风", "boy");
p1.showName();
p2.showName();
alert(p1.showName == p2.showName)
</script>
原型的优先级
<script type="text/javascript">
function Person(name, sex){
this.name = name;
this.sex = sex;
this.age = 18;
}
Person.prototype.showName = function(){
alert(this.name);
}
var p1 = new Person("小风儿", "boy");
p1.age = 20;
alert(p1.age);
</script>
Json
<script type="text/javascript">
//Json
//好处:1.结构件单,比较清晰
//坏处:2.无法批量创建对象
var person = {};
person.name = "";
person.sex = "";
person.showName = function(){
alert(this.name);
}
var person1 = person;
person1.name = "aaa";
var person2 = person;
person2.name = "zzz";
person1.showName();//zzz
person2.showName();//zzz
//变量之间传 数值
//对象之间传 地址; 数组是对象
</script>
Json 命名空间
<script type="text/javascript">
var Baidu = {};
Baidu.news = {
name : "zzz",
showName : function(){
return this.name;
}
};
Baidu.news.age = {
}
Baidu.news.showName = function(){
}
Baidu.vedio = {
name : "jjj",
showName : function(){
return this.name;
}
};
</script>
面向对象的拖拽
<style type="text/css">
#box_1 {
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
top: 0;
}
#box_2 {
width: 100px;
height: 100px;
background: green;
position: absolute;
left: 200px;
top: 0;
}
</style>
</head>
<body>
<div id="box_1"></div>
<div id="box_2"></div>
<script type="text/javascript">
//构造函数首字母大写
function Drag(id){
var _this = this; //Drag的实例化对象
//添加属性
//鼠标位置
this.mX = 0;
this.mY = 0;
//元素位置
this.bX = 0;
this.bY = 0;
//获取元素
this.oBox = document.getElementById(id);
//绑定鼠标事件
this.oBox.onmousedown = function(e){
var e = e || window.event;
_this.fnDown(e);
}
}
Drag.prototype.fnDown = function(e){
var _this = this; //Drag的实例化对象
//获取鼠标初始位置
this.mX = e.clientX;
this.mY = e.clientY;
//获取元素的初始位置
this.bX = this.oBox.offsetLeft;
this.bY = this.oBox.offsetTop;
document.onmousemove = function(e){
var e = e || window.event;
_this.fnMove(e);
}
this.oBox.onmouseup = function(){
_this.fnUp();
}
}
Drag.prototype.fnMove = function(e){
//获取当前的鼠标位置
var nowmX = e.clientX;
var nowmY = e.clientY;
//计算差值
var lessX = nowmX - this.mX;
var lessY = nowmY - this.mY;
//更新元素的偏移量
this.oBox.style.left = this.bX + lessX + "px";
this.oBox.style.top = this.bY + lessY + "px";
}
Drag.prototype.fnUp = function(){
document.onmousemove = null;
}
new Drag('box_1');
new Drag('box_2');
</script>
</body>
第二部分
Prototype模式
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。
这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function() {
alert("吃老鼠")
};
var cat1 = new Cat("大毛", "黄色");
var cat2 = new Cat("二毛", "黑色");
console.log(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
这时cat1和cat2会自动含有一个 constructor 属性,
指向它们的构造函数。
console.log(cat1.constructor == Cat); //true
console.log(cat2.constructor == Cat); //true
instanceof运算符, 验证原型对象与实例对象之间的关系。
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
这时所有实例的type属性和eat() 方法,
其实都是同一个内存地址, 指向prototype对象,
因此就提高了运行效率。
alert(cat1.eat == cat2.eat); //true
Prototype模式的验证方法
isPrototypeOf()
判断,某个proptotype对象和某个实例之间的关系。
alert(Cat.prototype.isPrototypeOf(cat1)); //true
hasOwnProperty() 有自己的属性
每个实例对象都有一个hasOwnProperty()方法,
用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
alert(cat1.hasOwnProperty("name")); // true
in运算符
1.判断某个实例是否含有某个属性,不管是不是本地属性。
alert("type" in cat1); // true
2.in运算符还可以用来遍历某个对象的所有属性。
for(var prop in cat1){
alert("cat1["+prop+"]="+cat1[prop]);
}
function Animal() {
this.species = "动物";
}
function Cat(name, color) {
//在extend方法中uber要在Cat中进行体现
Cat.uber.constructor.call(this);
this.name = name;
this.color = color;
}
构造函数绑定
function Cat(name, color) {
Animal.apply(this, arguments); //apply 数组
//Animal.call(this, species); //call 一个个的
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
prototype模式
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
console.log(Cat.prototype.constructor == Animal);
var cat1 = new Cat("大毛", "黄色");
console.log(cat1.species); // 动物
代码解析:
第一行:
将Cat的prototype对象指向一个Animal的实例;
相当于完全删除了prototype 对象原先的值,然后赋予一个新值;
任何一个prototype对象都有一个constructor属性,指向它的构造函数;
Cat.prototype.constructor指向Animal
第二行:所以加第二行
其实 每一个实例也有一个constructor属性,
默认调用prototype对象的constructor属性。
----------
小例子:
//父构造函数(父类)
function P1(name, sex){
this.name = name;
this.sex = sex;
}
P1.prototype.showName = function(){
alert("123123");
}
function P2(age){
this.age = age;
}
P2.prototype = new P1("中国人", "boy");
P2.prototype.constructor = P2;
var pp = new P2("18");
console.log(pp);
console.log(pp.name)
利用空对象作为中介
解决直接机继承浪费资源的问题
var F = function() {};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
代码解析
F是空对象, 所以几乎不占内存。
这时,修改Cat的prototype对象,
就不会影响到Animal的prototype对象。
封装上面
function extend(Child, Parent) {
var F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
extend(Cat, Animal);
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
封装方法最后一行解析:
子对象上打开一条通道, 可以直接调用父对象的方法。(备用)
拷贝继承
function Animal() {}
Animal.prototype.species = "动物";
function extend2(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for(var i in p) {
c[i] = p[i];
}
c.uber = p;
}
extend2(Cat, Animal);
var cat1 = new Cat("大毛", "黄色");
alert(cat1.species); // 动物
Javascript面向对象编程(三)非构造函数的继承
一、什么是”非构造函数”的继承?
这两个对象都是普通对象,不是构造函数,无法使用构造函数方法实现”继承”。
var Chinese = { //对象一: nation:'中国' };
var Doctor ={ //对象二: career:'医生' }
二、object()方法
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
把子对象的prototype属性,指向父对象
使用:
var Doctor = object(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); //中国
代码解析:
先在父对象的基础上,生成子对象:
然后,再加上子对象本身的属性:
这时,子对象已经继承了父对象的属性了。
三、浅拷贝
function extendCopy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
使用:
var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国
但是,这样的拷贝有一个问题。
如果父对象的属性等于数组或另一个对象,
那么实际上,子对象获得的只是一个内存地址,
而不是真正拷贝,因此存在父对象被篡改的可能。
例子:
Chinese.birthPlaces = ['北京','上海','香港'];
var Doctor = extendCopy(Chinese);
Doctor.birthPlaces.push('厦门');
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港, 厦门
所以,extendCopy()只是拷贝基本类型的数据,
我们把这种拷贝叫做"浅拷贝"。这是早期jQuery实现继承的方式
四、深拷贝
所谓”深拷贝”,就是能够实现真正意义上的数组和对象的拷贝。
它的实现并不难,只要递归调用”浅拷贝”就行了。
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
使用:
var Doctor = deepCopy(Chinese);
Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港