1、理解Object和Function
Object和Function都是引用类型,是一种数据结构,封装数据和功能,常常被称为类。
Object类型
既然是类,就可以用来创建对象,如 var person = new Object();
此外,JS中还提供另一个创建对象的方式:对象字面量,如 var persion = {};
上面两种方式的等价的。
Function类型
Function是类,它的对象是什么呢?其实就是我们常用的函数。没错,JS中的函数是对象,是Function类型的实例。如:
function sum(num1,num2){
return num1+num2
};
此外,JS还提供使用函数表达式定义函数的方式,如:
var sum = function(num1,num2){
return num1+num2;
};
- 函数的内部属性:
在函数内部,有两个特殊的对象:arguments和this,arguments是一个类数组对象,包含传入函数中的所有参数。这个对象还有有一个名叫callee的属性。该属性是一个指针,指向拥有这个arguments对象的函数。
ECMAScript5规范化了另一个函数对象的属性:caller,它保存着调用当前函数的函数的引用。
- 函数属性和方法:
每个函数都包含两个属性:length和prototype;length表示接受参数的个数;prototype保存函数类型的所有实例方法,相当与类方法,在自定义类型和实现继承时要特别注意。
每个函数还包含两个非继承而来的方法:apply()和call(),它们的区别在于接受参数的方式不同。这两个方法能扩充函数的作用域,使对象和方法解耦合。
2、理解原型对象
只要创建一个新函数,就会为该函数创建一个prototype属性,该属性指向函数的原型对象。下面通过实例代码和图说明。
首先通过构造函数和原型创建实例,代码如下:
function Person(){}
Person.prototype.name = 'xiaoming';
Person.prototype.sayName = function(name){alert(this.name)}
var p1 = new Person();
p1.sayName();// xiaoming
var p2 = new Person();
p2.sayName();// xiaoming
构造函数、原型对象即通过构造函数创建的实例对象之间的关系如下图所示:
3、理解原型链和继承
JS将原型链作为实现继承的主要方法,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。
原型链实现有一种基本模式,代码如下:
function Parent(){
this.property = true;
}
Parent.prototype.getParentValue = function(){
return this.property;
}
function Child(){
this.subproperty = false;
}
//子类继承父类
Child.prototype = new Parent();
Child.prototype.getSubValue = function(){
return this.subproperty;
}
var instance = new Child()
console.log(instance.getSubValue);
构造函数、原型对象即通过构造函数创建的实例对象之间的关系如下图所示:
这种模式实现继承有有个最大问题在于包含引用类型的原型,这可以通过组合继承解决,也就是组合原型链和构造函数,这种方式是JS中最常用的继承模式。背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数的方式实现对实例属性的继承。
实例如下:
function Parent(){
this.name = name;
this.colors = ['red','blue','green']
}
Parent.prototype.sayName= function(){
return this.name;
}
function Child(){
//继承属性
Parent.call(this,name);
this.age = age;
}
//继承方法
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.sayAge= function(){
return this.age;
}
var instance = new Child('xiaoming','28')
instance.colors.push("black");
consloe.log(instance.colors);// ['red','blue','green','black']
instance.sayName();//xiaoming
instance.sayAge();//28
var instance2 = new Child('xiaoli',30)
consloe.log(instance2.colors);//['red','blue','green']
instance2.sayName();//xiaoli
instance2.sayAge();//30
组合继承还是有个小问题,那就是多次调用超类型构造函数而导致的低效率问题。从而引出实现继承最有效的方式--寄生组合式继承
实例如下:
//借助原型基于已有对象创建对象
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritProtype(Parent,Child){
var prototype = object(Parent.prototype);//创建对象
prototype.constructor = Child;//增强对象
Child.prototype = prototype;//指定对象
}
function Parent(){
this.name = name;
this.colors = ['red','blue','green']
}
Parent.prototype.sayName= function(){
return this.name;
}
function Child(){
//继承属性
Parent.call(this,name);
this.age = age;
}
inheritProtype(Parent,Child);
Child.prototype.sayAge = function(){
return this.age
}
参考:JavaScript高级程序设计(第三版)