您的位置:首页 > Web前端 > JavaScript

[Javascript]:JS数据类型、类型判断、函数function与Function的使用

2017-09-13 00:24 731 查看
      因为之前学过Java,在学习JS时,对JS的数据类型、function和Function的使用概念容易搞混淆,理解不怎么深刻。遂将这些知识点和概念梳理一遍,以便自己和他人理解。如有错误,敬请谅解。

      知识点会涉及到:JS数据类型、JS的类型判断方式、函数创建方式、function与Function的区别、匿名函数的使用、函数特点以及函数重载问题。


Javascript数据类型

基本类型:undefined(未定义)、null(空)、number(数字)、string、boolean、symbol(新增的,没用过)
引用类型:object function
基本类型即值类型,引用类型即对象类型,和Java概念差不多。

在许多JS学习资料中,都会看见数据类型是以Undefined、Null、String...这种形式,而不是我上面的那种小写形式。关于这个问题,会进行解释。

这是因为在JS中,一切基于对象,所有事物都可以看作对象。这意味着在JS中使用的一切都是对象。给一个简单实例:给一个变量赋值,这个过程没用到new操作符创建相应对象,但却可以使用它的包装对象方法。如下:
<!-- 以字面量形式创建 -->
<script>
var a = 15;
var b = "abcde";
var len  = b.length;
var c = b.charAt(0);
document.write("长度:" + len + ", b索引字符:" + c);
//结果:长度:5, b:a
</script>
<!--以对象形式来创建 -->
<script>
var a = new Number(15);
var b = new String("abcde");
document.write(a.length + " , " + b.charAt(0)); //结果和上面一样,两者使用方式相同
</script> 


        上面的实例验证了:在JS中,直接使用值类型给变量赋值,JS也会把基本类型包装成相应对象,这时变量就是一个对象,所以才能直接使用方法。和Java相比,Java只有在需要值类型和包装类需要转换时才会自动进行装箱拆箱,否则严格按照本身定义的类型来使用,不会全部转成对象。所以搞明白JS中的一切都是对象这个概念后,包括变量、函数什么的都可以看作是对象。

       这时再来理解为什么数据类型都是大写而不是小写就很简单了。关于上面的基本类型,因为JS一切为对象的原则,所以undefined、null、object等就没有实际使用意义,上面写出来也只是为了搞明白它们之间的区别和相关概念。这些原始类型的作用仅仅是在使用 typeof 和 instanceof  用来判断具体类型,或是作为返回的字符串,用来表明该类型是什么,是基本类型还是引用类型,其他地方就用不到了~

所以,数据类型用对象类型来会更符合JS的定义:

Undefined、Null、Number、String、Boolean、Symbol、Object、 Function

Undefined表示的是一个变量被声明但是没有初始化,即没有赋值。值为undefined。
Null则和Java中概念差不多,唯一值是null,表示对象的引用地址为空。
关于Object和Function后面会说到,至于其他没什么可说的。
       


typeof 和 instanceof 的用法

typeof和instanceof都是运算符,它们都可以用来判断变量类型,但是它们各自的用法和操作对象又有所不同。

 typeof用法 

typeof 的返回值 和用于判断的值都是JS的原始类型,就是最上面写的那些类型。

typeof(var):获取指定变量的具体类型。

<!-- 使用typeof()来得到变量的原始类型,也可以直接 typeof var -->
<script>
var a = 15;
var b = "abcde";
var c = false;
var d = function(){} //这是一个函数
var e = new Function(); //这是一个函数对象
var f; //没赋值
document.write("a:" + typeof(a) + "<br>");
document.write("b:" + typeof(b) + "<br>");
document.write("c:" + typeof(c) + "<br>");
document.write("d:" + typeof(d) + "<br>");
document.write("e:" + typeof(e) + "<br>");
document.write("f:" + typeof f +",undef:"+typeof(undef)+ "<br>");
</script>
<!--结果
a:number
b:string
c:boolean
d:function
e:function
f:undefined,undef:undefined -->


typeof var === 'type' [b]对变量类型进行判断。[/b]

var a = 150;
var b = "abcde";
var c = false;
alert(typeof a === 'number');    //true
alert(typeof b === 'number');    //fasle
alert(typeof c === 'boolean');   //true
alert(typeof d === 'undefined'); //true


使用typeof判断对象类型变量时,都是返回object。

<script>
//定义两个构造函数
function cons1(){}
function cons2(){}
var a = new cons1();
var b = new cons2();
alert(typeof a === cons1);//false
alert(typeof b === cons2);//false
alert(typeof a);//object
alert(typeof b);//object
</script>


正因为typeof对于判断对象类型具有局限性,所以判断对象类型应使用insatanceof运算符。

 instanceof用法 

object instanceof Object2,instanceof运算符会判断指定对象类型的prototype

//定义两个构造函数
function cons1(){}
function cons2(){}
var a = new cons1();
var b = new cons2();
var aa = new Function(); //这是一个函数对象
var arr = []; //字面量创建数组
var arr2 = new Array();//数组对象创建数组
var obj = {name:"傲天", age:19}; //使用字面量创建对象
alert(a instanceof cons1); //返回true
alert(b instanceof cons2); //返回true
alert(aa instanceof Function); //返回true
alert(arr instanceof Object); //返回true
alert(arr instanceof Array); //返回true
alert(obj instanceof Object); //返回true
两者区别:

typeof用于判断基本类型,instanceof 用于判断对象类型。


function和Function区别,创建函数、函数特点

Function与function的区别:      

Function是一个功能完整的对象,作为JS的内置对象之一。而function只是一个关键字,用来创建一个普通函数或对象的构造函数。JS的普通函数都是Function对象的实例,所以函数本身也是一个对象,就像var一样,只不过这个对象具有可调用特征而已。

function创建对象和普通函数的区别:

如果用function创建构造函数,例如:var a = new function{}() 或者  var b = new Person();  则a、b就不是普通函数,而是作为一个真正对象,是Object类型。虽然普通函数也是对象,但一个是Function,作为函数;一个是Object,作为对象。 关于这个问题,可以使用instanceof运算符去验证。
本篇不会涉及使用function创建对象的相关知识,这里仅作了解。

注意:关键字function和原始类型的function名称是相同的,但就像object和Object一样,两者没半毛钱关系。一个是作为创建函数的关键字,一个是用来判断一个对象(函数)是不是Funtion类型。别搞混了。  

 创建函数的方式 

//  函数声明:使用function声明一个函数,再为其指定一个函数名。
function first(){
alert("函数声明方式");
}
//  函数表达式:使用function声明一个函数,但没有函数名,而是将这个函数赋给一个变量。也叫作匿名函数
var second = function(arg1, arg2){
alert(arg1+"|" + arg2+"\n匿名函数方式")
}
//  使用Function对象构造函数创建函数
var third = new Function(
"a1", "a2", "alert('函数对象,' + a1 + '|' + a2)"
);


调用函数方式可以有如下几种:

//  1.直接执行方式或采用事件来执行函数
first();
second("ABC", "XYZ");
third("火", "土");

//  2.函数也是对象,所以像变量一样.把函数名赋给另一个变量,那个变量就指向该函数地址
//  相当于再进行一次封装。动态添加对象方法时会用到。
var a = first;
var b = second;
a();
b("ABC", "XYZ");

//注意!这种方式是直接执行third()函数,而不是赋值函数名。
var c = third("火", "土");

三者的不同和优缺点:

函数声明在使用之前,就会被加载到作用域中,随时等待调用。而函数表达式(匿名函数)则是在代码执行到那一行才被定义,提前使用则会出错。
first(); //可以执行
function first(){
alert("函数声明方式");
}
second(15,25); //执行出错
var second = function(arg1, arg2){
alert(arg1+"|" + arg2+"\n匿名函数方式")
}

匿名函数(函数表达式)与Function()构造函数用法很相似,它们的不同点:匿名函数在使用时只被解析一次。而作为字符串传递给Function()构造函数的JS代码在每次调用构造函数时都要被解析和编译一次。Function对象的就是通过构造函数动态地创建和编译一个函数,但最好不要过多使用,因为用Function对象构造函数定义函数比其他两种慢多了。

 匿名函数 

匿名函数就是上面提到的函数表达式。匿名函数从字面意义来讲,就是没名字的函数,但它需要有一个依附体,要让匿名函数能被找到,不然的话没有意义。匿名函数看起来像Java的匿名内部类,但两者的使用方式差别巨大。但可以去了解一下,对于使用匿名函数或许有不一样的理解。
匿名函数除了可以赋值给一个var,用变量来调用匿名函数;还能把匿名函数赋给一个事件,作为事件处理程序,但别的函数方式也能达到这种效果。但匿名函数最特殊的地方是它的调用方式,下面会一一列举。
实例

// 定义一个匿名函数,依附于一个变量
var first = function(a1, a2){
alert(a1 + "|" + a2 + "\n变量名调用匿名函数")
}
//通过var名调用
first(111, 222);

//依附一个事件,随着事件触发而执行
window.onload = function () {
alert("页面加载完成后触发事件!");
}


上述匿名函数需要触发相关事件,或是主动执行。有没有匿名函数自动执行的方式呢?如下:
立即执行的匿名函数

//在匿名函数体后面加上(),表示立即执行该函数
var second = function(){
alert("代码执行到此处,立即执行。无需var()");
}(); //加分号表示执行完成,可加可不加。

//匿名函数有参,则往里面传参数
var second = function(a1, a2){
alert(a1 + "|" + a2 + "\n用括号给匿名函数传入参数,立即执行");
}(555,666);


因为函数本身也是对象,所以能赋给变量、事件,自然也能赋给一个对象。

//匿名函数赋给anyobj对象,然后anyobj再赋给second变量。这种方式没啥意义,了解原理即可。
var second = {
anyobj:function(msg){
alert(msg);
}("依附一个对象的匿名函数")
}


观察上述调用方式,它们都需要一个依附体(变量、事件等),然后这些对象会通过()调用匿名函数,这就是立即执行的匿名函数。但能不能换成别的依附体呢?让匿名函数看起来更像是匿名函数。如下:

//匿名函数放在括号体内
(
function(msg){
alert(msg + "\n匿名函数放在括号内,作为函数表达式");
}("传入参数")
);

这种调用方式是:外面括号包含匿名函数,然后调用()来立即执行函数。这种方式为什么能调用呢?这就要说到小括号的作用,外面的小括号相当于运算符,而此时匿名函数放在里面就形成了函数表达式,然后通过()就能调用该匿名函数。

从这个角度来看,我们还能使用其他运算符来执行匿名函数。

//使用一元运算符和匿名函数形成函数表达式
+function(msg){
alert(msg);
}("+")
-function(msg){
alert(msg);
}("-")
!function(msg){
alert(msg);
}("!")
~function(msg){
alert(msg);
}("~")
*function(msg){
alert(msg);
}("*")

      

      关于匿名函数的调用方式就说到这里,当然还有许多细节没说到,这里也仅仅是作为参考,至于还有没有其他运算符来执行匿名函数就不过多了解,最常用的也就是以上几种。最后想说,了解基本概念后,一定要多写,写得多自然也就理解了。

 JS函数的特点 

因为JS的弱类型特性,函数形参无法指定具体类型,返回类型自然也没有,return可以返回任何类型。
JS函数不限制传递的参数数量。这表明就算函数的参数列表已确定,照样可以传入多个参数。
JS函数没有重载,如果有同名函数,后一个会覆盖前一个。
实例
<script>
// 定义函数,返回传入的参数值
function getVal(val){
return val;
}
var a = getVal("传入val值", 200); //传入2个参数
//只定义了两个参数a,b 可以是任何类型
function method1(arg1, arg2){
console.log("method1函数值:" + arg1 + "," + arg2);
console.log("a值:" + a);
}
</script>
<!-- 往method1函数中传入4个参数 -->
<button onclick="method1(1, 'abc', 100, true)">点击</button>
<!-- 控制台输出
method1函数值:1,abc
a值:传入val值
-->

     通过上面,可以看到尽管定义函数时参数数量已确定,但依然可以往里面传入多个参数,JS不会对其进行检查。看起来无参函数和有参函数似乎没啥区别,反正参数可以随便传。但只有定义了形参,函数内部才能方便地使用定义好的形参。如果函数没有定义形参,你传入一堆参数给无参函数,函数内部无法直接拿到传入的参数值。这时候就只能通过函数内部的arguments对象来获取实参。

关于参数传入数量的问题:

如果传递的参数数量少于函数本身定义的形参数量时,之后的参数值都是undefined,因为没对其传值,就和定义了变量却没赋值一样。
如果是在强类型语言中,这种问题是没有的,所以要注意JS的特性。


 关于arguments对象 

arguments是每个函数内部都有的内部对象。函数所有接收的实参都由它来存储管理。取值方式和数组差不多。
<script>
//返回所有传入的参数
function getArgs(){
var all = "";
for(var i = 0; i < arguments.length; i++){
all += arguments[i] + " ";
}
return all;
}
function show(){
var allArgs = getArgs("我", 150, new Date(), "ABC", 555);
console.log(allArgs);
// 我 150 Wed Sep 13 2017 21:19:53 GMT+0800 (中国标准时间) ABC 555
}
</script>
<button onclick="show()">点击</button>
      通过上面实例,可以看到[b]arguments对象能拿到函数实参,无参函数通过arguments[0] 、argument[1]就能拿到传入的第一个实参和第二个实参。但这种获取实参方式不能乱用。如果规定了形参就使用形参,并且不要多传无用参数。而无参函数就别传入参数,一是无用,二是容易误导,代码写规范点总是没错的。[/b]

 JS函数为什么没重载 

首先,先了解重载需要具备的条件:方法名相同,但只要形参类型不相同或者形参数量不相同,都会导致方法重载。至于有无返回值则和重载条件无关。这样就会出现同名但方法不同。
在JS中,函数参数数量没法确定,而且参数类型可以是任意的,如果函数同名,后面的会覆盖前面的。所以JS函数没法实现重载。反过来想,如果JS函数可以重载,那就需要确定参数类型或者参数个数,那这样JS的动态类型就没实际意义了。但可以通过arguments得到参数长度来实现另类重载。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐