我觉得javascript是一种神奇的语言,随着逐步了解,会发现很多神奇的用法。
javascript是以函数为第一成员的解释性语言,也是面向过程的语言,但却可以神奇地演变成支持类型和对象。这就要提到原型(prototype)的概念。每个函数都有原型,而原型本身是一个对象,它包含这个函数对象的成员变量和成员方法。或者说,若把函数当成类型看待的话,原型就是承载成员变量和成员函数的东西。所以对象是没有原型的,而函数(类)本身也不能承载成员变量和成员函数。
像java 一样,javascript也有关键字this,它指向当前位置所属的作用域,而此作用域是一个对象,默认情况下,this指向window,即当前窗口对象。
function Func1(){
//this指向window
console.log('this is ' + this);
if(arguments.length > 0){
return 'My first argument is ' + arguments[0];
}else{
return ' I have no argment ';
}
}
当this是处在一个类(通过函数的原型添加成员,或在函数体内通过this.添加成员)中时,this就是指通过此类创建的对象。
//创建类的三种方式,this都指向所在类创建的对象,而非window.
function ClassA(){
console.log('this is ' + this);
this.name = 'ClassA';
this.run = function(){
return 'My name is ' + this.name;
};
this.myFunc = function(){};
}
function ClassB(){
console.log('this is ' + this);
name = 'ClassB';
return {
run:function(){
return 'My name is ' + this.name;
}
}
}
function ClassB(){}
ClassB.prototype.run = function(){
console.log('this is ' + this);
}
javascript中对象的成员可以访问哈希表一样访问,这样的灵活性使对象的成员扩展变得很灵活。方法Object.assign可以用来扩展成员。
基于这三个语言特性,我们在不使用新版的class关键字的情况下,建立javascript的类型体系。
//定义最顶级类,用于js继承基类
function Class() { }
//顶级类方法默认空方法(当前还不是真正的构造函数)
Class.prototype.constructor = Class;
Class.extend = function (def) {
var oc = Object.prototype.constructor;
var subClass = {};
if(def.constructor != oc){//定义了自己的构造函数
subClass = def.constructor;
} else {//若未定义自己的构造函数,则使用父类构造函数
subClass = this.apply(this,def);
}
//原型对象
var proto = new this();
for (var n in def) {
proto[n] = def[n];
}
subClass.prototype = proto;
//此为父类原型
var superClass = this.prototype;
subClass.superClass = superClass;
//赋给这个新的子类同样的静态extend方法
subClass.extend = this.extend;
return subClass;
};
类型为Class类体系中的顶层类,可以通过extend方法来定义子孙类.
//类Animal 继承自Class
var Animal = Class.extend({
action:'walk',
constructor: function (name) {
Animal.superClass.constructor.call(this);
this.name = name || "Animal";
},
eat: function (food) {
console.log("Father." + this.name + '正在吃:' + food);
},
sleep: function () {
console.log("Father." + this.name + '正在睡觉!');
}
});
// 类Cat继承自Animal
var Cat = Animal.extend({
love:'fish',
constructor: function () {
Cat.superClass.constructor.call(this,"Cat");
console.log('Cat constructor');
},
eat: function (food) {
console.log("SubClass." + this.name + '正在吃:' + food);
Cat.superClass.eat.call(this, food);
},
sleep: function () {
console.log("SubClass." + this.name + '正在睡觉!');
Cat.superClass.sleep.call(this);
}
});
可以通过下面测试来判断继承关系,以及对覆盖方法后对父类相同方法的调用。
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
参考:Extjs3.4中类型扩展。