[Javascript]:JS数据类型、类型判断、函数function与Function的使用
2017-09-13 00:24
731 查看
因为之前学过Java,在学习JS时,对JS的数据类型、function和Function的使用概念容易搞混淆,理解不怎么深刻。遂将这些知识点和概念梳理一遍,以便自己和他人理解。如有错误,敬请谅解。
知识点会涉及到:JS数据类型、JS的类型判断方式、函数创建方式、function与Function的区别、匿名函数的使用、函数特点以及函数重载问题。
基本类型:undefined(未定义)、null(空)、number(数字)、string、boolean、symbol(新增的,没用过)
引用类型:object function
基本类型即值类型,引用类型即对象类型,和Java概念差不多。
在许多JS学习资料中,都会看见数据类型是以Undefined、Null、String...这种形式,而不是我上面的那种小写形式。关于这个问题,会进行解释。
这是因为在JS中,一切基于对象,所有事物都可以看作对象。这意味着在JS中使用的一切都是对象。给一个简单实例:给一个变量赋值,这个过程没用到new操作符创建相应对象,但却可以使用它的包装对象方法。如下:
上面的实例验证了:在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用法
typeof 的返回值 和用于判断的值都是JS的原始类型,就是最上面写的那些类型。
typeof(var):获取指定变量的具体类型。
typeof var === 'type' [b]对变量类型进行判断。[/b]
使用typeof判断对象类型变量时,都是返回object。
正因为typeof对于判断对象类型具有局限性,所以判断对象类型应使用insatanceof运算符。
instanceof用法
object instanceof Object2,instanceof运算符会判断指定对象类型的prototype
typeof用于判断基本类型,instanceof 用于判断对象类型。
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()构造函数的JS代码在每次调用构造函数时都要被解析和编译一次。Function对象的就是通过构造函数动态地创建和编译一个函数,但最好不要过多使用,因为用Function对象构造函数定义函数比其他两种慢多了。
匿名函数
匿名函数就是上面提到的函数表达式。匿名函数从字面意义来讲,就是没名字的函数,但它需要有一个依附体,要让匿名函数能被找到,不然的话没有意义。匿名函数看起来像Java的匿名内部类,但两者的使用方式差别巨大。但可以去了解一下,对于使用匿名函数或许有不一样的理解。
匿名函数除了可以赋值给一个var,用变量来调用匿名函数;还能把匿名函数赋给一个事件,作为事件处理程序,但别的函数方式也能达到这种效果。但匿名函数最特殊的地方是它的调用方式,下面会一一列举。
实例
上述匿名函数需要触发相关事件,或是主动执行。有没有匿名函数自动执行的方式呢?如下:
立即执行的匿名函数
因为函数本身也是对象,所以能赋给变量、事件,自然也能赋给一个对象。
观察上述调用方式,它们都需要一个依附体(变量、事件等),然后这些对象会通过()调用匿名函数,这就是立即执行的匿名函数。但能不能换成别的依附体呢?让匿名函数看起来更像是匿名函数。如下:
这种调用方式是:外面括号包含匿名函数,然后调用()来立即执行函数。这种方式为什么能调用呢?这就要说到小括号的作用,外面的小括号相当于运算符,而此时匿名函数放在里面就形成了函数表达式,然后通过()就能调用该匿名函数。
从这个角度来看,我们还能使用其他运算符来执行匿名函数。
关于匿名函数的调用方式就说到这里,当然还有许多细节没说到,这里也仅仅是作为参考,至于还有没有其他运算符来执行匿名函数就不过多了解,最常用的也就是以上几种。最后想说,了解基本概念后,一定要多写,写得多自然也就理解了。
JS函数不限制传递的参数数量。这表明就算函数的参数列表已确定,照样可以传入多个参数。
JS函数没有重载,如果有同名函数,后一个会覆盖前一个。
实例
通过上面,可以看到尽管定义函数时参数数量已确定,但依然可以往里面传入多个参数,JS不会对其进行检查。看起来无参函数和有参函数似乎没啥区别,反正参数可以随便传。但只有定义了形参,函数内部才能方便地使用定义好的形参。如果函数没有定义形参,你传入一堆参数给无参函数,函数内部无法直接拿到传入的参数值。这时候就只能通过函数内部的arguments对象来获取实参。
关于参数传入数量的问题:
如果传递的参数数量少于函数本身定义的形参数量时,之后的参数值都是undefined,因为没对其传值,就和定义了变量却没赋值一样。
如果是在强类型语言中,这种问题是没有的,所以要注意JS的特性。
在JS中,函数参数数量没法确定,而且参数类型可以是任意的,如果函数同名,后面的会覆盖前面的。所以JS函数没法实现重载。反过来想,如果JS函数可以重载,那就需要确定参数类型或者参数个数,那这样JS的动态类型就没实际意义了。但可以通过arguments得到参数长度来实现另类重载。
知识点会涉及到: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得到参数长度来实现另类重载。
相关文章推荐
- javascript数据变量类型判断(JS变量是否是数组,是否是函数的判断)
- javascript 简单高效判断数据类型系列函数
- 【前端js】实现一个函数可以对JavaScript中的5种主要数据类型进行赋值
- 【JS数据类型】JS中的判断数据类型函数
- JavaScript常用工具函数(验证数据格式、清除空格、判断浏览器类型、cookie操作等)
- javascript 简单高效判断数据类型 系列函数 By shawl.qiu
- js基础--变量、数据类型、循环、判断、函数定义
- js 中的类型判断函数 isObject isFunction
- JAVASCRIPT随记-使用偏函数判断对象类型
- javascript 简单高效判断数据类型 系列函数 By shawl.qiu
- JavaScript——判断js数据类型(类型检测)
- javascript数据类型和函数的简单的使用
- javascript 简单高效判断数据类型系列函数 (转) By shawl.qiu
- 20180301:JavaScript的初步学习,JS的数据类型与变量,函数,DOM操纵HTML,BOM操作浏览器
- eval解析JSON中的注意点 在JS中将JSON的字符串解析成JSON数据格式,一般有两种方式: 1.一种为使用eval()函数。 2. 使用Function对象来进行返回解析。 使用eval
- 【js基础】javascript中关于数据类型一些知识和类型判断
- javascript 简单高效判断数据类型 系列函数 By shawl.qiu
- JavaScript数据类型判断--使用toString方法
- JavaScript 学习day01 (js的特点,组成,使用,语法和数据类型)
- isArray()函数(JavaScript中判断对象类型的种种方法)