Javascript中本身没有“类”,“实例”,“继承”的概念
可通过new Object()
或json方式
创建一个对象
下面介绍
- 使用原型和构造函数模拟类,创建对象
- 使用原型链和伪装函数组合模拟继承,创建子对象
类
使用function
,prototype
和constructor
模拟
(参考Javascript继承机制的设计思想)
function Xxx(args){...}
- 构造函数
- 通过
this.名称
设置实例对象不需要共享的属性和方法(this代表新创建的实例对象)
- 通过
- 内置了一个
prototype属性
,指向一个prototype对象
- 通过
Xxx.prototype.名称
设置此prototype对象
中存放实例对象需要共享的属性和方法 - 任何一个
prototype对象
都有一个constructor属性
,指向它的构造函数
- 通过
- 构造函数
调用
new 构造函数(args)
从prototype对象
生成一个实例对象- 实例对象的属性和方法,分成本地的和继承自prototype对象的
- 所有的实例对象共享同一个
prototype对象
- 每一个实例有一个
_prop_
属性,指向prototype对象
定义类:
function Person(){}
Person.prototype={
constructor:Person,
name:"leon",
age:22,
say:function(){
alert(this.name+" "+this.age);
}
}
function Person
中有一个prototype属性
,指向Person prototype对象
Person prototype对象
中有一个constructor属性
,指向function Person
- 所以可以通过
new Person()
创建对象 - 注意:使用
json
方式构建prototype,需手动指定constructor,若不写,则默认指向Object - 原型内存模型:
创建对象,并测试:
var p1=new Person();
p1.say(); // leon 22
var p2=new Person();
p2.name="Ada";
p1.say(); // leon 22
p2.say(); // Ada 22
- 通过
new Person()
创建的对象会有一个_prop_
属性,指向Person prototype对象
- 使用
对象.xxx
访问对象属性或方法时- 先在对象内查找调用
- 若对象内没有,就会通过
_prop属性
去Person prototype对象
中查找 - eg:
p1.name
返回leon
(Person prototype对象
中的值)p2.name
返回Ada
(p2对象定义的值)
- 注意:这个
_prop_
属性外部是不能访问的
- 原型内存模型:
检测对象:
Person.prototype.isPrototypeOf(p1); //true
p1.hasOwnProperty("name"); //false
//检测某个属性是否在对象中(对象空间或原型空间)
alert("name" in p1); //true
alert("address" in p2); //false
Person.prototype.isPrototypeOf(p2); //true
p2.hasOwnProperty("name"); //true
for(var prop in p1) { alert("p1["+prop+"]="+p1[prop]); }
isPrototypeOf()
:判断某个proptotype对象和某个实例之间的关系hasOwnProperty()
:判断某一个属性是否是本地属性in
运算符- 判断某个实例是否含有某属性,不管是不是本地属性
- 还可以用来遍历某个对象的所有属性
注意:
若在Person prototype对象
中定义的属性为引用类型,可能会影响到其他对象获取的值,例如:
Person.prototype.firends=["Tom","Jerry"];
p1.friends.push("LiLi");
console.log(p1.friends); //["Tom","Jerry","LiLi"];
console.log(p2.friends); //["Tom","Jerry","LiLi"];
建议在construct中定义属性,在prototype中定义方法:
function Person(){
this.friends=["Tom","Jerry"];
}
Person.prototype={
constructor:Person,
...
}
继承
父类:
function Parent(name){
this.name=name;
this.color=["red","blue"];
}
Parent.prototype={
constructor:Parent,
ps:function(){
alert(this.name+" "+this.color);
}
}
子类:
function Child(name,age){
//调用父类构造方法,构造子类属性
Parent.call(this);
this.age=age;
}
//使用原型链继承,让Child prototype指向Parent对象
Child.prototype=new Parent();
Child.prototype.say=function(){
alert(this.name+" "+this.age+" "+this.color);
}
创建对象,并测试:
var c1=new Child("leon",22);
var c2=new Child("Ada",23);
c1.color.push("green");
c1.ps(); // leon ["red","blue","green"]
c1.say(); // leon 22 ["red","blue","green"]
c2.ps(); // Ada ["red","blue"]
c2.say(); // Ada 23 ["red","blue"]
内存模型:
闭包
定义的函数:
- 使用
function xxx(){...}
(会先被初始化):fn(); function fn(){ ... }
- 使用
var xxx=function(){...}
:fn2(); // 会报错 var fn2=function(){ ... }
闭包:
通过返回函数来扩大函数的作用域的方式
function func(){
...
return function(){
...
}
}
创建匿名函数并调用(建议这样放入全局变量,控制在一个作用域中):
(function(){
//...
})()
使用举例:
类中设置私有变量(即没有this.xxx
定义,无法通过对象.xxx
获取和更改)
var Person;
//调用匿名函数(在匿名函数中进行类和私有变量的定义)
(function(){
var name=""; //在此匿名函数外部无法获取,且在函数结束时销毁
Person=function(name){
name=name;
};
Person.prototyep.setName=function(name){
name=name;
};
Person.prototype.getName=function(){
return name;
}
})();
测试:
var p1=new Person("Tom");
p1.getName(); //Tom
p1.setName("Lucy");
p1.getName(); //Lucy
//p1.name为undefined,无法获取到