乐趣区

胡说-JavaScript函数类型

回到了自己的家乡,期待中有感觉到了很多的陌生,一个有“故事”的环境中,你我是否“孤独”!
函数的类型
在我看来 function 共有三种类型,作为对象使用,处理业务以及穿件 object 的实例对象。跟这三种用法相对应的有三种子类型,分别是对象的属性、变量(包括参数)和创建出来的 object 类型实例对象的属性。这三种子类是相互独立的,而且也很容易区分。但是,我们刚刚接触的时候很容易混淆。
1.function 作为对象来使用
这种情况下,function 对象的子类型就是对象自己的属性,这时通过操作符“.”(或者方括号操作符) 使用,示例如下:
function book(){}
book.price=999;
book[“getPrice”]=function(){
return this.price;
}
console.log(book.getPrice()); // 输出结果:999
我很少碰到 function 来作为 object 类型的对象来使用。
2.funciton 用于处理业务
这种情况下,function 的子类型就是自己定义的局部变量(包括参数),这时的变量实在方法被调用时通过变量作用域链来管理的。关于变量我之前的文档中有涉及到,这里就不过多的说明了。
3.function 用于创建对象
这种情况下,对应的子类型是使用 function 创建实例对象的属性(很常用),主要包括在 function 中通过 this 添加属性,以及创建完成之后实例对象自己添加的属性。另外,还可以调用 function 的 prototype 属性对象所包含的属性,示例如下:
function Car(color,displacement){
this.color = color;
this.displacement = displacement;
}
Car.prototype.logMessage = function(){
console.log(this.color+”,”+this.displacement);
};
var car = new Car(“yellow”,”2.4T”);// 看看是不是类似构造函数?哈哈
这个例子中创建的 car 对象就包含有 color 和 displacement 两个属性,而且还可以调用 Car.prototype 的 logMessage 方法。当然,创建完之后还可以使用点操作符给创建的 car 对象添加或者修改属性,也可以使用 delete 删除其中的属性,示例如下:
function Car(color,displacement){
this.color = color;
this.displacement = displacement;
}
// 所有创建出来的 car 都有该方法
Car.prototype.logMessage = function(){
console.log(this.color+”,”+this.displacement);
};
var car = new Car(“yellow”,”2.4T”);// 看看是不是类似构造函数?哈哈
// 给 car 对象添加属性
car.logColor = function(){
console.log(this.color);
};
// 完成调用测试
car.logColor();// 输出结果:yellow
car.color = “red”;
car.logColor();// 输出结果:red
delete car.color;// 删除属性
car.logColor();// 输出结果:undefined

代码分析:在创建完 car 对象之后,又给它添加了 logColor 的方法,可以打印 car 的 color 属性。添加完 logColor 方法后直接调用就可以打印出 car 原来的 color 属性值(yellow)。然后,将其修改为 red,在打印出了 red。最后,使用 delete 删除 car 的 color 的属性,这时在调用 logColor 方法会打印出 undefined
其实跟我的注释说明一致!!!

三种子类型的关系
function 的三种子类型是相互独立的,他们只能在自己所对应的环境中使用而不能相互调用,示例如下:
function log(msg){// 第二种业务处理
console.log(msg);
}
function Bird(){
var name = “kitty”;
this.type = “pigeon”;
this.getName = function(){
return this.name;// 创建的对象没有 name 属性
}
}
Bird.color = “white”;// 第一种 object 类型的对象
Bird.getType = function(){// 第一种 object 类型的对象
return this.type;
};
Bird.prototype.getColor = function(){// 第三种创建对象
return this.color;
}
var bird = new Bird();
log(bird.getColor());// undefined
log(bird.getName()); // undefined
log(bird.getType()); // undefined
Bird 作为对象时包含 color 和 getType 两个属性,作为处理业务的函数是包含一个名为 name 的局部变量,创建的实例对象 bird 具有 type 和 getName 两个属性,而且还可以调用 Bird.prototype 的 getColor 属性,getColor 也可以看作 bird 的属性。

用 法
子 类 型

对象(Bird)
color、getType

处理业务(Bird 方法)
name

创建实例对象(bird)
type、getName、(getColor)

每种用法中所定义的方法只能调用相对应所对应的属性,而不能交叉调用,从对应关系中可以看出,getName、getColor 和 getType 三个方法中无法获取到值,大家再仔细分析一下!
另外,getName 和 getColor 是 bird 的属性方法,getType 是 Bird 的属性方法,如果用 Bird 对象调用 getName 或 getColor 方法或者使用 bird 对象调用 getType 方法都会抛出找不到的错误。
三种子类型不可以相互进行调用之外,还有一种情况也非常重要:那就是对象的属性并没有继承的关系。
function obj(){}
obj.v=1;
obj.func = {
logV : function(){
console.log(this.v);
}
}
obj.func.logV();
代码分析:这个例子中的 obj 是作为对象使用的,obj 是有一个属性 v 和一个对象属性 func,func 对象中又有一个 logV 方法,logV 方法用于打印对象的 v 属性。这里需要特别注意:
logV 方法打印的是 func 对象的 v 属性,但是 func 对象中并没有 v 属性,所以最后结果是 undefined。
这个例子中,虽然 obj 对象中包含 v 属性,但是由于属性不可以继承,所以 obj 的 func 属性对象中的方法不可以使用 obj 中的属性 v.
请大家一定要记住,并且不要和 prototype 的继承以及变量作用域链相混淆

关联三种子类型
三种子类型本来是相互独立、各有各的使用环境的,但是,有一些情况下需要操作不属于自己所对应环境的子类型,这时就需要使用一些技巧来实现了。
约定如下

function 作为对象使用时记作 O(Object)
作为函数使用时记作 F(Function)
创建出来的对象实例记作 I(Instance)
op(object property)
v(variable)
ip(instance property)

op
v
ip

O
直接调用
在函数中关联到 O 的属性
不可调用

F
使用 O 调用
直接调用
不可调用

I
使用 O 调用
在函数中关联到 I 的属性
直接调用

纵向表头表示 function 的不同用法

横向表头表示三种类型,表格的主体表示在 function 相应用法中调用各种子类的方法。
因为 function 创建的实例对象在创建之前还不存在,所以 function 作为方法(F)和作为对象(O)使用时无法调用 function 创建的实例对象的属性(ip)。调用参数可以在函数中将变量关联到相应的属性,调用 function 作为对象(O)时的属性可以直接使用 function 对象来调用

function log(msg){
console.log(msg);
}
function Bird(){
// 私有属性
var name = “kitty”;
var type = “pigeon”;
// 将局部变量 name 关联到新创建的对象的 getName,setName 属性方法
// 闭包可以使用局部变量
// 公有属性
this.getName = function(){
return name;
}
this.setName = function(n){
name = n;
}
// 将局部变量 type 关联到 Bird 对象 getType 属性方法
// 静态属性
Bird.type = function(){
return type;
}
// 在业务处理中调用 Bird 对象的 color 属性
log(Bird.color);// 输出结果:white,F 调用 op

}
Bird.color = “white”;// 代表 O
// 在创建出的实例对象中调用 Bird 对象的 color 属性
Bird.prototype.getColor = function(){//I
return Bird.color;//OP
}
var bird = new Bird(); // 创建实例 I
log(bird.getColor()); // 输出结果:white,I 调用 op
log(bird.getName());// 输出结果:kitty , I 调用 v 局部变量
log(Bird.getType());// 输出结果:pigeon , O 调用 v 局部变量
bird.setName(“petter”); // I 调用 v
log(bird.getName());// 输出结果:petter , I 调用 v 局部变量
好好分析上述的代码,非常经典的,了解三种子类型的不同环境用法中交叉调用的方法
附录:“公有属性”“私有属性”和“静态属性”
上面的示例中我们涉及到了公有属性、私有属性和静态属性的说明,由于 JS 并不是基本类而是基于对象的语言,因此 JS 本身并没有这些概念。

公有属性:一般指使用 function 对象创建出 object 实例对象所拥有的属性。
私有属性:一般指 function 的内部变量
静态属性:一般指 function 对象自己的属性

退出移动版