1.构造函数
例:Animal = function(name,age){
this.name = name;
this.age = age;
}
var animal = new Animal("cat",5);
alert(animal.name+" "+animal.age);
2.模拟静态属性
例:Animal = function(name,age){
this.name = name;
this.age = age;
Animal.insCont++;
}
Animal.insCont = 0;
var animal = new Animal("cat",5);
alert(Animal.insCont+" "+animal.insCont);// 1 undefined
function的静态属性,和Java类静态属性最大的区别就是,前者的实例对象不能访问function类的静态属性。只能用类名(function的名字)直接调用。
3.定时器:setTimeout和setInterval。前者只执行一次,后者每隔相同的时间就执行,除非取消。取消定时器的方法分别为:clearTimeout和clearInteral.
例:var myFn = function(){
var date = new Date();
document.body.innerHTML = date.toLocaleString();
}
window.setTimeout(myFn,1000); // 只更新一次
window.setInterval(myFn,1000); // 每1秒钟更新
另外一种写法:直接把函数写在第一个参数的位置
window.setInterval(function(){
var date = new Date();
document.body.innerHTML = d.toLocaleString();
},1000);
Ext.util.TaskRunner和Ext.TaskMgr就用到了上述内容。
4.给回调函数传参(这里需要重点理解)。上例中myFn就是一个回调函数。“回调”的直观理解就是:不是让脚本引擎现在就执行,而是我们设置好放在这里,一旦需要的时候你在“回过头来”调用。
window.setInterval(myFn,1000);不是立即执行myFn,而是每隔一秒钟的时间,再来调用它。
现在的问题是,怎么给myFn传递参数?
window.setInterval(myFn("cat"),1000); // 这种做法是错误的,因为里面的("cat")是一个运算符,当JS执行到这一行的时候,直接就调用了myFn这个函数,而不是由定时器调用。
解决办法就是:把第一个参数myFn("cat")写在一个函数里面,封装起来。
var myFn = function(){
var date = new Date();
document.body.innerHTML = date.toLocaleString();
}
window.setTimeout(function(){
myFn("cat")
},1000); // 只更新一次
这样就,每个1秒执行function(){ myFn("cat") }这个函数,这个函数就会调用myFn并且传参。我们把这个函数提取出来,就变成了下面的形式:
var myFn = function(){
var date = new Date();
document.body.innerHTML = date.toLocaleString();
}
var callBack = function(name){
return function(){
myFn(name);
}
}
window.setTimeout(callBack("cat"),1000);
这样,当脚本引擎执行到最后一行的时候,先执行callBack("cat"),返回function(){myFn("cat");},这样每隔1秒钟就执行myFn("cat")。
接下来把callBack这个函数给抽象出来就变成:
var myFn = function(){
var date = new Date();
document.body.innerHTML = date.toLocaleString();
}
var callBack = function(fn,args){
return function(){
fn.call(window,args); // window绑定fn的this
}
}
window.setTimeout(callBack(myFn,"cat"),1000);
5.函数原型prototype
例:var obj = {};
alert(obj.prototype); // undefined 注意不是抛出异常
alert(obj.constructor);// function Object(){ [native code] }
说明:1 var obj = {};其实是调用了Object构造函数。
2 普通的JS对象实例,没有prototype这个属性。
3 obj.constructor是Object的构造函数。
4 实例可以通过某个机制,能够访问其构造函数的prototype的属性和方法。但是,普通对象不能对其构造函数的prototype属性进行修改。
6.向prototype添加自定义属性
例:Animal = function(name){
this.name = name;
}
Animal.prototype.sayHello = function(){
alert("hello,my name is:" + this.name);
}
var animal = new Animal("cat");
animal.sayHello();
效果和下面相同:
Animal = function(name){
this.name = name;
this.sayHello = function(){
alert("hello,my name is:" + this.name);
}
}
var animal = new Animal("cat");
animal.sayHello();
但是,前者只是给类Animal生成一份sayHello方法,后者会给每一个实例对象都生成一份sayHello方法。prototype方式的优点可想而知。
7.原型查找机制。以上述为例,sayHello这个函数被“存储”在了Animal.prototype上,animal实例上并没有sayHello这个方法。这时候依据JS的“原型查找”机制:如果从实例对象上没有找到指定的属性,那么就尝试从它的构造函数的prototype上去找;如果找不到,继续找prototype构造函数的prototype。直到找到了为止,否则返回null终止。
例:Animal = function(name){
this.name = name;
}
Animal.prototype.sayHello = function(){
alert("my name is :" + this.name);
}
Cat = function(name){
this.name = name;
}
Cat.prototype = new Animal("animal");
var cat = new Cat("cat");
cat.sayHello(); // my name is :cat
流程如下:首先在cat对象上找sayHello方法,没有找到,尝试到Cat.prototype上去找。此时,Cat.prototype已经被赋值成了new Animal("animal")实例,还是没有找到,又到Animal.prototype上去找,找到即返回。
但是,为什么结果显示"cat"而不是"animal"?因为在Cat的构造函数中有this.name = name;根据原型查找机制的规则会首先检测对象自身的属性,当没有检测到自身的属性的时候才回去原型上去找。
这是不是闻到了一点儿Java中继承的味道?
8. 重写,相当于Java的override。根据之前的查找机制很容易理解
例:Animal = function(name){
this.name = name;
}
Animal.prototype.sayHello = function(){
alert("my name is:"+ this.name);
}
var cat = new Animal("cat");
cat.sayHello = function(){
alert("my name is :"+ cat.name); //cat
}
cat.sayHello(); // 调用实例对象自己的sayHello方法。
9.原型赋值机制
例:Animal = function(){}
var a1 = new Animal();
Animal.prototype.name = "cat";
alert(a1.name); // cat
var a2 = new Animal();
alert(a2.name); // cat
虽然,在new出了a1这个对象之后才向Animal.prototype动态添加了name属性,a1.name还是被赋了值。说明:首先,实例对象的属性也是按照运行时的“查找”机制去查找的,否则a1.name为undefined。其次,向prototype添加、删除属性会“立即”影响到所有对象实例。查找机制:如果对象上找不到属性,则会到原型上去找。而对于赋值机制:只能在确定的地方赋值,而且给实例对象赋值是不会影响到prototype的。