function a(s){//定义以s为参数的函数,返回s的值 s=100; return s; } var y=1; a(y);//y作为参数调用函数a console.log(y);//y还是为1
结果还是1因为把y的值给s时是简单的复制了一份,y和s可以单独操作不相互影响
(2)复杂数据类型作为参数时,函数内部对参数值的修改会改变外部变量的值
因为复杂数据类型赋值是把栈中对象的地址赋给变量,函数内外两个变量指向同一个对象,所以只要对象的属性值改变,两个变量值都会改变
function student(age,name,agrde){ this.age=age; this.name=name; this.score=agrde; } var s1=new student(18,"wjq",2);//创建一个student对象 function a(s){ s.name=”xxx”; } a(s1)//把s1赋给s console.log(s1.name);//输出xxx
原始类型和对象的区别主要还是在内存中的保存形式,要弄懂js中简单数据类型和复杂数据类型的区别,关键还要搞懂两个在内存中的存储过程。
JavaScript有三种方法,可以确定一个值到底是什么类型。
最常用的是 typeof 运算符,返回一个值的数据类型有以下几种结果:
// 变量声明了,但没有赋值 var i; i // undefined // 调用函数时,应该提供的参数没有提供,该参数等于undefined function f(x) { return x; } f() // undefined // 对象没有赋值的属性 var o = new Object(); o.p // undefined // 函数没有返回值时,默认返回undefined function f() {} f() // undefined
typeof false // "boolean" typeof true // "boolean"
typeof '345' // "string"
typeof 345 // "number"
var s1=new Object(); typeof s1 //"object" var arr1=[1,2,3]; typeof arr1 //"object" var pattern= /at/g; typeof pattern //"object" typeof null // "object"
var f= function() {}; typeof f //"function"
instanceof是判断指定对象是否为某个构造函数的实例,返回值是true
或false
。
var v = new Object(); v instanceof Object // true
上面代码中,对象v是构造函数Object的实例,所以返回true。
instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象,是否在左边对象的原型链上。因此,下面两种写法是等价的。
v instanceof Object // 等同于 Object.prototype.isPrototypeOf(v)
由于instanceof对整个原型链上的对象都有效,因此同一个实例对象,可能会对多个构造函数都返回true。
var d = new Date(); d instanceof Date // true d instanceof Object // true
上面代码中,d同时是Date和Object的实例,因此对这两个构造函数都返回true。 instanceof的原理是检查原型链,对于那些不存在原型链的对象,就无法判断。
null instanceof Object // false
由于null 没有 prototype,即不存在原型,因此instanceof就认为该对象不是Object的实例。
JavaScript 之中,只要是对象,就有对应的构造函数。因此,instanceof运算符的一个用处,是判断值的类型。
var x = [1, 2, 3]; var y = {}; x instanceof Array // true y instanceof Object // true
上面代码中,instanceof运算符判断,变量x是数组,变量y是对象。
注意,instanceof运算符只能用于对象,不适用原始类型的值。
var s = 'hello'; s instanceof String // false
上面代码中,字符串不是String对象的实例(因为字符串不是对象),所以返回false。
此外,对于undefined和null,instanceOf运算符总是返回false。
undefined instanceof Object // false null instanceof Object // false
用法上的区别:
typeof 对数组 [] 和对象 {} 的返回值都是Object,无法区分数组和对象,但是instanceof可以区分。
var a = {}; var b=[]; typeof a // "object" typeof b // "object" a instanceof Array // false a instanceof Object // true b instanceof Array // true b instanceof Object // true
使用typeof 运算符可以判断一个变量是否是数字、字符串、布尔、函数。
数字
var a=1; typeof a // 'number'
字符串
var b="string"; typeof b // "string"
布尔
var c=true; typeof c //true
函数
var f=function() {}; typeof f // "function"
NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
100 - 'a' // NaN
上面代码运行时,会自动将字符串a转为数值,但是由于a不是数值,所以最后得到结果为NaN,表示它是“非数字”(NaN)。
需要注意的是,NaN不是一种独立的数据类型,而是一种特殊数值,它的数据类型依然属于Number,使用typeof运算符可以判断出来。
typeof NaN // 'number'
NaN不等于任何值,包括它本身。
NaN === NaN // false
由于数组的indexOf方法,内部使用的是严格相等运算符,所以该方法对NaN不成立。
[NaN].indexOf(NaN) // -1
NaN在布尔运算时被当作false。
Boolean(NaN) // false
NaN与任何数(包括它自己)的运算,得到的都是NaN。
NaN + 12 // NaN NaN - 12 // NaN NaN * 12 // NaN NaN / 12 // NaN
isNaN方法可以用来判断一个值是否为NaN。isNaN()函数接受一个参数,该参数可以是任何类型,而函数会判断这个参数是否"不是数值"。isNaN()在接收到一个值之后,会尝试将这个值转换为数值。某些不是数值的值会直接转换为数值,例如"10"和"Boolean"。而任何不能被转换为数值的值都会导致这个函数返回true。
isNaN(NaN) // true isNaN(123) // false isNaN("123") // false isNaN("123string") // true
isNaN只对数值有效,如果传入其他值,会被先转成数值。
出于同样的原因,对于对象和数组,isNaN也返回true。
isNaN({}) // true // 等同于 isNaN(Number({})) // true isNaN(['xzy']) // true // 等同于 isNaN(Number(['xzy'])) // true
但是,对于空数组和只有一个数值成员的数组,isNaN返回false。
isNaN([]) // false isNaN([123]) // false isNaN([123,567]) // true isNaN(['123']) // false
上面代码之所以返回false,原因是这些数组能被Number函数转成数值。
判断NaN更可靠的方法是,利用NaN是JavaScript之中唯一不等于自身的值这个特点,进行判断。
function IsNaN(value) { return value !== value; }
有三个函数可以把非数值转换为数值:
转型函数Number()可以用于任何数据类型,而另外两个函数则专门用于把字符串转换成数值。
Number函数的转换规则:
Number(true) //1 Number(false) //0
Number(3.14) //3.14
Number(null) // 0
Number(undefined) // 0
5.如果是字符串,遵循下列规则:
Number ('23') // 23 Number ('+23') // 23 Number ('-23') // -23 Number ('011') // 11 前面的0会忽略
Number ('3.14') //3.14 Number ('03.14') //3.14
Number ('0x10') // 16
Number ('') // 0
Number("123blue") // NaN Number(message) // NaN,变量message未声明
parseInt
方法用于将字符串转为整数。返回值只有两种可能,不是一个十进制整数,就是NaN。parseInt ('120') //120 整数转化成整数 parseInt ('3.14') //3 浮点数转化前面的整数部分 parseInt (' 10') //10 前面的空格会忽略 parseInt ('000010') //10 前面的0会忽略
parseInt(1.23) // 1 // 等同于 parseInt('1.23') // 1
parseInt('8a') // 8 parseInt('12**') // 12 parseInt('12.34') // 12 parseInt('15e2') // 15 parseInt('15px') // 15 //上面代码中,parseInt的参数都是字符串,结果只返回字符串头部可以转为数字的部分。
parseInt('abc') // NaN parseInt('.3') // NaN parseInt('') // NaN parseInt('+') // NaN parseInt('+1') // 1
parseInt('1000', 10) // 1000 以十进制解读(默认) parseInt('1000', 2) // 8 以二进制解读 parseInt('1000', 6) // 216 以六进制解读 parseInt('1000', 8) // 512 以八进制解读 parseInt('10', 37) // NaN 进制超出范围,就返回 NaN parseInt('10', 1) // NaN 进制超出范围,就返回 NaN parseInt('10', 0) // 10 parseInt('10', null) // 10 parseInt('10', undefined) // 10 第二个参数是0、null、undefined 则直接忽略
parseFloat('3.14') // 3.14 浮点数转浮点数 parseFloat('314e-2') // 3.14 parseFloat('0.0314E+2') // 3.14 如果字符串符合科学计数法,则进行相应转换 parseFloat ('3.14abc') // 3.14 如果字符串包含不能转换为浮点数的字符,则不再往后转换,返回已经转好的部分。 parseFloat (' 3.14') // 3.14 parseFloat ('00003.14') // 3.14 parseFloat方法会自动过滤字符串前面的空格
parseFloat([]) // NaN 空数组返回 NaN parseFloat('FF2') // NaN 第一个字符不能转化浮点数 parseFloat('') // NaN 空字符串转化为 NaN
parseFloat () 和 Number () 的区别
parseFloat(true) // NaN Number(true) // 1 parseFloat(null) // NaN Number(null) // 0 parseFloat('') // NaN Number('') // 0 parseFloat('123.45#') // 123.45 Number('123.45#') // NaN
区别(1):parseFloat()转换时,第一个小数点有效,小数点对parseInt()无效
parseFloat("22.34.5") //22.34 parseInt("22.34.5") //22
区别(2):parseFloat()始终会忽略前导的0
parseFloat()可以识别前面讨论过的所有浮点数值格式,也包括十进制整数格式。但十六进制格式的字符串则始终会被转换成0。由于parseFloat()直解析十进制值,因此它没有用第二个参数指定基数的用法。最后还要注意一点,如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后都是0),parseFloat()会返回整数。
parseFloat("1234blue") //1234 parseFloat("0xA") //0 parseFloat("22.5") //22.5 parseFloat(22.34.5) //22.34 parseFloat("0908.5") //908.5 parseFloat("3.125e7") //31250000 parseFloat("4.0000") //4
确定两个变量是否相等是编程中的一个非常重要的操作。在比较字符串、数值和布尔值的相等性时,问题还比较简单。但在涉及到对象的比较时,问题就变得复杂了。最早的ECMAScript中的相等和不等操作符会在执行比较之前,先将对象转换成相似的类型。后来,有人提出了这种转换到底是否合理的质疑。最后,ECMAScript的解决方案就是提供两组操作数:相等和不相等——先转换在比较,全等和不全等——仅比较而不转换。
1.相等和不相等
这两个操作符都会先转换操作数,然后再比较它们的相等性。
在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:
false == 1 //false false == 0 //true true ==1 //true true == 0 //false
"123" == 123 //true
这两个操作符在进行比较时则要遵循下列规则。
null == undefined //true
null +1 //1 undefined +1 //NaN null == 0 //false undefined == 0 //false
"NaN" == NaN //false NaN == NaN //false NaN != NaN //true
2.全等和不全等
全等操作符只在两个操作数未经转换就相等的情况下返回true。
除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。
"55" == 55 //true,因为转换后相等 "55" === 55 //false,因为在不转换的情况下,字符串不等于数值 null ==undefined //true null === undefined //false
记住,null ==undefined会返回true,因为它们是类似的值;但null === undefined会返回false,因为它们是不同类型的值。
var num = 0; for (var i=1; i<10; i++) { if (i % 5 == 0) { break; } num++; } alert(num); //4
var num = 0; for (var i=1; i<10; i++) { if (i % 5 == 0) { continue; } num++; } alert(num); //8
break和continue语句都可以与label语句联合使用,从而返回代码中特定的位置。这种联合使用的情况多发生在循环嵌套的情况下。
var num = 0; outermost : for (var i=0; i<10; i++) { for (var j=0; j<10; j++) { if (i ==5 && j == 5) { break outermost; } num++; } } alert(num); //55
break语句后面带了一个参数:要返回到的标签。添加这个标签的结果将导致break语句不仅会退出内部的for语句(使用变量j
的循环),而且也会退出外部的for语句(使用变量i
的循环)。
var num = 0; outermost : for (var i=0; i<10; i++) { for (var j=0; j<10; j++) { if (i ==5 && j == 5) { break; } num++; } } alert(num); //95
var num = 0; outermost : for (var i=0; i<10; i++) { for (var j=0; j<10; j++) { if (i ==5 && j == 5) { continue outermost; } num++; } } alert(num); //95
continue语句后面带了一个参数:要返回到的标签。添加这个标签的结果将导致continue语句会退出内部循环(这也就意味着内部循环少执行了5次),执行下一次外部循环(continue退出的是单次循环,继续执行下一次循环)。
var num = 0; outermost : for (var i=0; i<10; i++) { for (var j=0; j<10; j++) { if (i ==5 && j == 5) { continue; } num++; } } alert(num); //99
var undefined = 10; // undefined -- chrome // 弹出10 -- IE 8,低版本IE中 alert(undefined);
(function() { //局部作用域 var undefined = 10; //弹出 10 -- chrome alert(undefined); })(); (function() { //全局变量并赋值,因为在全局作用域undefiend不能被重写,所以赋值无效 undefined = 10; // 弹出undefined -- chrome alert(undefined); })();
void 运算符能对给定的表达式进行求值,然后返回 undefined。
也就是说,void 后面你随便跟上一个表达式,返回的都是 undefined,都能完美代替 undefined。
那么,这其中最短的是什么呢?毫无疑问就是 void 0 了。其实用 void 1,void (1+1),void (0) 或者 void “hello”,void (new Date()) 等等,都是一样的效果。更重要的前提是,void 是不能被重写的(cannot be overidden)。
ES5 大环境下,void 0 也有可以发挥作用的地方,用 void 0 代替 undefined 就能节省不少字节的大小。事实上,不少 JavaScript 压缩工具在压缩过程中,正是将 undefined 用 void 0 代替掉了。
(1)以下代码的输出结果是?为什么?
console.log(1+1);//输出2,两个数字加法运算 console.log("2"+"4");//输出'24',两个字符串类型的做字符串拼接 console.log(2+"4");//输出'24',一个是数字一个是字符串,数字转化为字符串后拼接 console.log(+"4");//输出4,只有一个字符串会转换成数字输出
var a = 1; a+++a; // 3 等同于 (a++)+a,这里前面的(a++)为1,后面的a为2,++优先级高于+ typeof a+2; // 'number2' 等同于(typeof a)+2,前面为字符串‘number’,后面数值,拼接成字符串,typeof 优先级高于+
var a = 1; var b = 3; console.log( a+++b ); // 4 括号里面等同于(a++)+b,前面的(a++)表达式值为1,先用a的值,用完后再给a自加1
(2)遍历数组,把数组里的打印数组每一项的平方
var arr = [3,4,5] for (var i=0;i<3;i++){ console.log(arr[i]*arr[i]) } // 9 16 25
(3)遍历 JSON, 打印里面的值
var obj = { name: 'hunger', sex: 'male', age: 28 } for(a in obj){ console.log(a+":"+obj[a]) } // name:hunger sex:male age:28
(4)下面代码的输出结果
var a = 1, b = 2, c = 3; var val = typeof a + b || c >0 // 优先级顺序typeof + > || console.log(val) // 'number2' || true // 输出‘number2’ var d = 5; var data = d ==5 && console.log('bb') // console.log('bb') 输出了字符串bb,但它的返回值是undefined console.log(data) // data = true && undefined //输出 undefined var data2 = d = 0 || console.log('haha') // console.log('haha') 输出了字符串haha,但它的返回值是undefined console.log(data2) // data2 = d = 0 || undefined //输出 undefined var x = !!"Hello" + (!"world", !!"from here!!"); // true+(false, true),即true+true console.log(x) // console.log (true+true) // 输出 2
补充:
逗号运算符用于对两个表达式求值,并返回后一个表达式的值。
'a', 'b' //返回"b" var x = 0; var y = (x++, 10); x //1 y //10
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句