标签:javascript 面向对象编程 面向对象 对象 继承
进阶面向对象——————————————————————–
在JS源码中,系统对象也是基于原型的程序,
尽量不要去添加和修改系统对象的方法
包装对象——————————————————————–
基本类型都有自己对应的包装对象
比如String Number Boolean
基本类型会找到对应的包装对象类型,然后包装对象把所有的属性方法给了
基本类型,然后包装对象消失
例如
var str = ‘abc‘;
str.num = 10;
//创建一个包装对象,给包装对象加num属性,然后立刻消失。
//除非设置String.prototype.num = 10;
alert(str.num);
//这时候又创建了一个包装对象,和上面创建的那个没有关联,
//所以显示undefined
原型链————————————————————————-
实例对象与原型之间的连接,叫做原型链
在ff中的DOM能查看到:__proto__( 隐式连接 )
对于一个对象来说,调用其方法或使用其属性,它会先看自己有没有该
方法/属性,如果没找到,再通过__proto__向上查找它的原型,直至
最顶层的原型Object
Object对象类型是原型链的最外层
Object.prototype
面向对象的一些常用属性和方法—————————————————
obj.hasOwnProperty(‘name‘) : 查看对象/属性是否是对象本身的。
该方法是 Object.prototype的方法
constructor : 查看对象的构造函数
还可以用来判断对象的类型 如:
var str = ‘‘;
alert(str.constructor===String);//true
另外,当声明一个构造函数时,系统会自动给xxx.prototype.constructor
赋值,如:
function Person(){
}
系统会自动加上 Person.prototype.constructor=Person;
而且这是面向对象系统自动生成的唯一一段代码
但是如果用JSON
Person.prototype = {
attr1 : 10,
fn1 : function(){}
}
来给Person加对象加属性/方法的话,会覆盖系统自动生成的代码。
导致对象实例化以后,实例化对象.constructor 会通过原型链
(因为本构造函数没有这个属性)找到Object.constructor,从而
得到的值是Object
因此用JSON给对象写原型属性/方法时,要先给对象写construct
属性,并指向本身
For in 的时候有些系统自带属性prototype属性是找不到的
(自己添加的找得到)
避免修改construtor属性
instanceof : 对象与构造函数在原型链上是否有关系
用法:
person1 instanceof Person 在原型链上有关系就返回true
也可以用来判断对象是否是指定的属性
var arr = [];
arr instanceof Array //true
toString() :
把对象转为字符串
是Object上的方法
系统对象下面的这个方法都是自带的,而自己写的对象都是通过
原型链找到Object下面的方法
Array对象的toString:返回数组的字符串形式
Number对象的toString(n):返回数字n进制的字符串形式
利用toString做类型的判断(最好)
var arr=[];
alert( Object.prototype.toString.call(arr) );//[Object Array];
Object.prototype.toString.call(arr)===‘[Object Array]‘;
为真则是数组
总结判断对象类型的三种方法:
obj.constructor === Array;
obj instanceof Array;
//以上两个在跨iframe,判断window.frames[i].Array;时不行
Object.prototype.toString.call(obj) === ‘[Object Array]‘;
继承—————————————————————————
概念 : 在原有对象的基础上,略作修改,得到一个新的对象
不影响对象原有功能。
好处 : 子类不影响父类,子类可以继承父类的一些功能 (代码复用)
写法 :
属性继承:调用父类的的构造函数.call():
function Person(name,sex){
this.name = name;
this.sex = sex;
}
function Star(name,sex,job){
Person.call(this,name,sex);
//如果不改变this指向,function下的Person中的this指向window
this.job = job;
}
原型方法/属性的继承:
【拷贝继承】
父类的原型拷贝一份赋给子类,
这样就不会因为JS的引用机制,子类修改的原型属性方法影响父类
Star.prototype = deepCopy(Person.prototype);
【类式继承】
JS中没有类的概念,可以把构造函数等价于java中的类
类式继承写法:
function Father(){
this.name = ‘大明‘;
};
Father.prototype.callname = function(){
alert(this.name);
};
function Child(){};
Child.prototype = new Father();//核心
var c1 = new Child();
c1.callname();//大明
原理:c1本身没有callname方法,于是找Child上的callname方法
Child.prototype上面也没有callname方法,于是找到new Father()
这个匿名对象上,这个实例对象本身也没有该方法,要通过原型链找到
Father.prototype上的callname方法,然后再调用
问题:
Child.prototype = new Father();一句话覆盖了Child所有的prototype
,就连Child.prototype.constructor也被覆盖了,所以
c1.constructor也找不到了,要通过原型链找到其父级的constructor,
所以c1.constructor的值是Father。
因此为避免这个问题要手动修正Child.prtotype.constructor=Child;
此外,把this.name改为数组[1,2,3];
创建一个实例对象对其进行操作
var c1 = new Child();
c1.name.push(4);
var c2 = new Child();
alert(c2.name);//1,2,3,4
由此发现两个不同的实例对象居然会相互之间产生影响
原因是无论是c1还是c2,他们在读取name属性时都是在本身找不到,
而要通过原型链到匿名实例对象new Father()上找。所以操作的
是同一个地址。进而产生影响。
要避免这个问题,就要做到属性和方法分开继承。
function F(){};//1
F.prototype = Father.prototype;//2
Child.prototype = new F();//3
Child.prototype.constructor = Child;//4
//以上是类式继承的4句话
1句中声明的F构造函数没有属性。2句中F只继承了Father的原型方法,
自己并没有属性。3句中把一个F的实例对象赋值给Child的原型。
这样,如果实例化Child->c1调用c1.name,只能向上找F的实例对象上
有没有name这个属性,而由2句可知,F的实例对象是没有name这个属性
的,所以系统只会返回undefined
而如果c1调用方法callname,系统会通过原型链一直找到Father.prototype
从而调用Father.prototype上的callname方法。所以属性和方法继承
被分开了。
而继承属性的方法还是在Child构造函数中调用Father.call(this);
【原型继承】
function Father(){
this.name = ‘父亲‘;
}
var f1 = new Father();
var c1 = cloneObj(f1);
c1.name = ‘小米‘
//alert(c1.name)//小米
//alert(f1.name)//父亲
var a = {
name : ‘a‘
};
var b = cloneObj(a);
b.name = ‘b‘;
alert(b.name);
alert(a.name);
function cloneObj(obj){
function F(){};
F.prototype = obj;
return new F();
}
【三种继承方式总结】
拷贝继承:通用型的 有new或无new的时候都可以使用
类式继承:适合new 构造函数
原型继承:适合无new的形式
版权声明:本文为博主原创文章,转载还请留言。
标签:javascript 面向对象编程 面向对象 对象 继承
原文地址:http://blog.csdn.net/u014420383/article/details/47678929