//JS该如何检测数据的类型呢?
//使用关键字: typeof
//输出结果依次为:'number','string','boolean'.
1 console.log(typeof 17); 2 console.log(typeof '17'); 3 console.log(typeof true);
//输出结果依次为:'object','undefined'
1 console.log(typeof null); 2 console.log(typeof undefined);
//可知:null 是object类型。
//输出结果依次为:'number','object'. 可以设想一下String('17'),new String('17');
1 console.log(typeof Number(17)); 2 console.log(typeof new Number(17));
//输出结果依次为:'string','object'
1 console.log(typeof String('17')); 2 console.log(typeof new String('17'));
//同理:'boolean','object'。
1 console.log(typeof Boolean(true)); 2 console.log(typeof new Boolean(true));
//Why ?
//使用new 关键字是构造新的对象。new Number()是构建一个number对象。
//new Number(17) 是17 的包装类型对象。而单纯的Number(17)是强制转换,是转型函数。
//使用new调用基本包装类型的构建函数与直接调用同名的转型函数是不一样的。
//再看下面的实例,依次输出:false,true,false
1 console.log((17) instanceof Number); 2 console.log(new Number(17) instanceof Number); 3 console.log(Number(17) instanceof Number);
//在Java编程中,我们都知道针对原始类型,Java API都提供对应包装对象。
//那么JS编程中,JS针对三种原始类型也提供了对应的包装对象:Number,String,Boolean.
//同理适用于String,Boolean.
//接着往下看。
//输出结果为:'object','object','function'
1 console.log(typeof []); 2 console.log(typeof {}); 3 console.log(typeof function(){});
//'object',阴魂不散,真令人讨厌。
//问题来了,该如何准确的判断这些'object'呢?
//先介绍下call,apply 方法。
//在JS中,函数是一等公民。即可构建对象,又可作为值来使用。
//声明函数很简单
1 function f1(){ 2 console.log("声明函数使用关键字function"); 3 } 4 function f2(num1,num2){ 5 console.log("这是带二个参数的函数。"+num1+num2); 6 } 7 function f3(who){ 8 console.log("hello "+who); 9 return "我是有返回值的函数"; 10 }
//调用函数相当简单:一对圆括号,如果需要参数就附带上参数。
f1();f2(1,2);console.info(f3('china'));
//关于函数表达式,函数作为值,在后面讲闭包时在讲。
//关于函数参数
1 function test(num1,num2){ 2 console.log(num1); 3 num1=10; 4 console.log(arguments[0]+" "+num2); 5 arguments[0]=2; 6 console.log(num1+" "+num2); 7 console.log(arguments instanceof Array); 8 console.log(arguments.toString()); 9 } 10 test(0,1);
//在JS中,系统有一个叫作:arguments的东东进行维护函数的参数。argument不是Array的实例。
//但是arguments拥有类似数组的特性:比如可以使用方括号语法访问参数的元素,
//拥有length属性获取参数的个数。
1 function f4(arg1,arg2,arg3){ 2 console.log(arguments.length); 3 for(var index=0,length=arguments.length;index<length;index++){ 4 console.log(arguments[index]); 5 } 6 } 7 f4('中国',"福建"); 8 f4('I ','am ','dylan'); 9 f4('I ','am ','dylan','!!!');
//正是因为有arguments类数组管理参数,所以在参数传递时JS不会去考虑参数的个数。
//同时请观察test函数,可以发现num1与argument[0]值不仅相等,而且是同步改变的。
//在传统面向对象编程中,构建函数是可以重载的,但是在JS中没有重载。
//function 也是对象。
console.log(function(){} instanceof Object);
//扩展一下,既然function是对象,那么函数名就是指向函数的指针了。
//既然是对象就必有相应的属性与方法,function拥有length,prototype属性(此属性后续再讲)
//拥有apply,call方法。
1 function testLength1(){ 2 console.log("testLength1.length="+testLength1.length); 3 console.log("没有参数,因此length为0。"); 4 console.log("arguments.callee.length="+arguments.callee.length); 5 } 6 function testLength2(name){ 7 console.log("testLength2.length="+testLength2.length); 8 console.log("有一个参数,参数长度为1"); 9 console.log("arguments.callee.length="+arguments.callee.length); 10 console.log("arguments.length="+arguments.length); 11 } 12 13 testLength1(); 14 testLength2(); //注意 15 testLength2("dylan"); 16 console.info(testLength1.length); 17 console.info(testLength2.length);
//一目了然了吧:length属性表示函数希望接收的命名参数的个数。
//arguments是个类数组,它主要作用是管理函数的参数。
//arguments.callee代表当前函数名,在本例中就是:testLenght2.
//使用argument.callee在递归中很有帮忙。感兴趣同学可以去探索一下。
//函数的length属性与函数调用时实际接收到的参数值并不一定相等。
//每个function都有二个方法:apply,call. 作用是执行指定函数(对象)的上下文。
1 var o1 ={ 2 name: 'dylan', 3 getName: function(){ 4 return this.name; 5 }, 6 setName: function(greet,name){ 8 return greet+" , "+ name 9 } 10 } 11 12 var o2 ={ 13 name: 'bady', 14 getName: function(){ 15 return this.name; 16 } 18 } 19 //var o3={name:'hello'}; 20 var o3={};
//调用o1的getName的方法,指定的上下文对象是o3,而o3没有name属性,所以返回undefined.
console.log(o1.getName.call(o3));
//调用o1的getName的方法,此的上下文对象是o2。所以返回bady.
console.log(o1.getName.call(o2));
//call与apply区分不大,主要在于apply 参数为数组。
1 console.log(o1.setName.call(o2,'Hi',' tony ')); 2 console.log(o1.setName.apply(o2,['Hi',' fred '])); 3 //console.log(o1.setName.apply(o2,'Hi',' fred '));
//ok,说了这么多,现在回归typeof
1 function toType(type){ 2 if(arguments.length==0){ 3 return ; 4 } 5 if((typeof type)!=='object'){ 6 return typeof type; 7 } 8 9 //return ({}).toString.call(type); 10 return ({}).toString.call(type).match(/s(w+)/)[1]; 11 } 12 console.log(toType([12])); 13 console.log(toType({})); 14 console.log(toType(function(){})); 15 console.log(toType(17)); 16 console.log(toType('17')); 17 console.log(toType(false)); 18 console.log(toType(new Number(17))); 19 console.log(toType(null)); 20 console.log(toType(undefined)); 21 console.log(toType(String("dylan")));
//toType还可以这样优化。
//return ({}).toString.call(type).match(/s(w+)/)[1];
//最后还可以调用toLowerCase方法。
//return ({}).toString.call(type).match(/s(w+)/)[1].toLowerCase();