分析JavaScript的数据类型与变量

发表于:2018-11-16 10:43

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:swpuLeo    来源:segmentfault

分享:
  这篇文章,我们来聊聊 JS 中的数据类型与变量。这是最基础的一类问题,但却很重要。
  比如:
  如何理解参数的按值传递?
  什么是暂时性死区?
  什么是变量提升?
  全局变量和 window 的属性有什么区别?为什么?
  ... ...
  以上的问题均来自面试。如果你并不清楚,我觉得你有必要接着读下去。
  基本数据类型
  在 JS 中,基本数据类型有 6 种,即数值、字符串、布尔值、null、undefined、Symbol。
  对于基本数据类型,我们需要明白的是:基本类型在内存中的存储方式是栈。每一个值都是单独存放,互不影响。
  基本类型都是按值访问的。在比较时,按值进行比较:
 1 === 1 // true
  引用数据类型
  引用类型的值保存在堆中,而引用是保存在栈中。
  引用类型按引用访问。在比较时,也比较的引用:
{} === {} // => false
  参数的传递方式
  在 JS 中,参数可以是任何类型的值,甚至可以是函数。
  这里要分析的是参数是以哪种类型传递的?引用类型还是基本类型?
  先看一个基础的例子:
   var out_num = 1;
  function addOne(in_num) {
  in_num += 1;
  return in_num;
  }
  addOne(out_num); // => 2
  out_num // => 1
  这个例子中,我们给 addOne() 函数传递一个实参 out_num,这个时 out_num 会传递给 in_num,即内部存在着 in_num = out_num 的过程。最后我们看到的结果是 out_num 并没有被函数改变,说明 in_num 和 out_num 是两个在内存中独立存放的值,即按值传递。
  再来看一个变形:
   var out_obj = { value: 1 };
  function addOne(in_obj) {
  in_obj.value += 1;
  return in_obj;
  }
  addOne(out_obj); // => { value: 2 }
  out_obj // => { value: 2 }
  问题来了?函数参数不是按值传递吗?为什么这里函数内部的处理反映到外部了?这是一个超级超级超级的理解误区。
  首先,我们还是得摆正观点,即函数参数是按值传递的。那这里怎么理解呢?对于引用类型而言,前面说引用类型分为引用和实际的内存空间。在这里 out_obj 依旧传递给 in_obj,即 in_obj = out_obj ,out_obj 和 in_obj 是两个引用,它们在内存中的存储方式是独立的,但是它们却指向同一块内存。
  而 in_obj.value = 1 则是直接操作的实际对象。实际对象的改变,会同步到所有引用这个实际对象的引用。
  你再来看这个例子,或许就会更清晰一些。
   var out_obj = { value: 1 };
  function addOne(in_obj) {
  in_obj = { value: 2 };
  return in_obj;
  }
  addOne(out_obj); // => { value: 2 }
  out_obj // => { value: 1 }
   你只要抓住一点:对象的赋值就会造成引用指向的实际对象发生改变。
  如何判断数据类型
  判断数据类型,通常有三种具体的方法:
  1、typeof 操作符
  typeof 操作符返回一个表示数据类型的字符串。它存在以下明显的缺陷:
   typeof null // => 'object'
  typeof [] // => 'object'

    这是因为在 JS 语言设计之初遗留的 bug。可以阅读这篇文章 http://2ality.com/2013/10/typ... 了解更多关于 typeof 处理 null 的问题。
  所以 typeof 最好用于判断一些基本类型,比如数值、字符串、布尔值、undefined、Symbol。
  2、instanceof 操作符
  typeof 的背后是通过判断 type tags 来判断数据类型,而 instanceof 则是通过判断构造函数的 prototype 是否出现在对象原型链上的任何位置。
  举个例子:
   {} instanceof Object // => true
  [] instanceof Array // => true
  [] instanceof Object // => true
  也判断自定义类型:
  function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
  }
  var auto = new Car('Honda', 'Accord', 1998);
  console.log(auto instanceof Car);
  // => true
  console.log(auto instanceof Object);
  // => true
  所以,对于字面量形式的基本数据类型,不能通过 instanceof 判断:
   1 instanceof Number // => false
  Number(1) instanceof Number // => false
  new Number(1) instanceof Number // => true
  3、Object.prototype.toString()
  这是目前最为推荐的一种方法,可以更加精细且准确的判断任何数据类型,甚至是 JSON、正则、日期、错误等等。在 Lodash 中,其判断数据类型的核心也是 Object.prototype.toString() 方法。
Object.prototype.toString.call(JSON) // => "[object JSON]"
  关于这背后的原理,你可以阅读这篇文章 http://www.cnblogs.com/ziyunf...
  4、其他
  上面三种是通用的判断数据类型的方法。面试中还会出现如何判断一个数组、如何判断 NaN、如何判断类数组对象、如何判断一个空对象等问题。这一类问题比较开放,解决思路通常是抓住判断数据的核心特点。
  举个例子:判断类数组对象。
  你先要知道 JS 中类数组对象是什么样子的,并寻求一个实际的参照物,比如 arguments 就是类数组对象。那么类数组对象具有的特点是:真值 & 对象 & 具有 length 属性 & length 为整数 & length 的范围大于等于 0,小于等于最大安全正整数(Number.MAX_SAFE_INTEGER)。
  在你分析特点的时候,答案就呼之欲出了。【注意全面性】
  数据类型如何转换
  JS 数据类型的动态性将贯穿整个 JS 的学习,这是 JS 非常重要的特性,很多现象就是因为动态性的存在而成为 JS 独有。
  正是由于动态性,JS 的数据类型可能在你毫无察觉的情况下,就发生了改变,直到运行时报错。
  这里主要分析下面 8 种转换规则。
  1、if 语句
  if 语句中的类型转换是最常见的。
   if (isTrue) {
  // ...
  } else {}
  在 if 语句中,会自动调用 Boolean() 转型函数对变量 isTrue 进行转换。
  当 isTrue 的值是 null, undefined, 0, NaN, '' 时,都会转为 false。其余值除 false 本身外都会转为 true。
  2、Number() 转型函数
  我们重点关注 null undefined 以及字符串在 Number() 下的转换:
   Number(null) // => 0
  Number(undefined) // => NaN
  Number('') // => 0
  Number('123') // => 123
  Number('123abc') // => NaN
  注意和 parseInt() 对比。
  3、parseInt()
   parseInt(null) // => NaN
  parseInt(undefined) // => NaN
  parseInt('') // => NaN
  parseInt('123') // => 123
  parseInt('123abc') // => 123  4、==
  这里需要注意的是:
   null == undefined // => true
  null == 0 // => false
  undefined == false // => false
  null 与 undefined 的相等性是由 ECMA-262 规定的,并且 null 与 undefined 在比较相等性时不能转换为其他任何值。
  5、关系操作符
  对于两个字符串的比较,是比较的字符编码值:
'B' < 'a' // => true
  一个数值,另一个其他类型,都将转为数字进行比较。
  两个布尔值转为数值进行比较。
  对象,先调用 valueOf(),若不存在该方法,则调用 toString()。

    上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号