JS变量类型和计算

更新:慕课 前端技术一面 第四章

思考过程

  • 拿到一个面试题,第一时间看到的是什么->考点
  • 又如何看待网上搜出来的永远也看不完的题海->不变应万变
  • 如何对待接下来遇到的面试题?->题目到知识再到题目

一些面试题和考察的知识点

  • JS中使用typeof能得到的哪些类型?【JS变量类型】
  • 何时使用===何时使用==【强制类型转换】
  • window.onloadDOMContentLoaded的区别?【浏览器渲染过程】
  • 用JS创建10个<a>标签,点击的时候弹出来对应的序号【作用域】
  • 简述如何实现个模块加载器,实现类似require.js的基本功能【JS模块化】
  • 实现数组的随机排序 【JS基础算法】

变量类型和计算

变量类型

  • 值类型VS引用类型
  • typeof运算符详解

值类型(基本数据类型)

  • 基本类型的值是不可变的
    • 任何方法都无法改变一个基本类型的值,比如一个字符串:
      1
      2
      3
      //调用了toUpperCase()方法后返回的是一个新的字符串
      var name = 'hello';
      name.toUpperCase(); //输出HELLO
  • 不能给基本类型添加属性与方法:
    1
    2
    3
    4
    5
    var person = 'Mary';
    person.age = 22;
    person.method = function(){};
    console.log(person.age); //underfined
    console.log(person.method);//underfined
  • 基本类型的变量和值都是存放在栈内存中:
    1
    2
    3
    4
    var a = 200;
    var b = a;
    b = 21;
    console.log(a); //200

值类型中变量b相当于深拷贝了变量a,a和b是两个不同的存在。所以改变a以后b不变。


引用类型(引用/对象数据类型)

  • 除了基本类型就是引用类型,也就是说对象。对象是属性与方法的集合。也就是说引用类型可以拥有属性与方法,属性又可以包含基本类型与引用类型
  • 引用类型的值是可变的,我们可以为引用类型添加属性与方法,也可以删除其属性与方法。如:
    1
    2
    3
    4
    5
    6
    var person = {}; //创建一个对象 ---引用类型
    person.name = 'Mary';
    person.age = 22;
    person.sayName = function() {console.log(person.name);}
    person.sayName(); //'Mary'
    delete person.name; //删除person对象的name属性
  • 引用类型将引用名称存储在栈内存中,真实的数据存放在堆内存里:栈内存与堆内存
    • 例子:
      1
      2
      3
      4
      var a = { age: 20 };
      var b = a;
      b.age = 21;
      console.log(a.age); //21

引用类型中变量b和变量a都是指针,他们同样都指向同一个属性age,所以他们其实是共享属性age的。所以改变b的age属性相当于改变a的age属性

对象、数组、函数 是引用类型,这是因为如果他们的内容很多,采用 值类型 就要 复制 ,那就很耗内存,为了让内存共用(节省)空间,所以才存在 引用类型。


typeof运算符

typeof能得到的6种类型:number、undefined、string、boolean、object、function。
(注意:null 空指针,也是一个对象)

但是,typeof运算符 只能区分 值类型

1
2
3
4
typeof undefined;//undefined
typeof "hlz";//string
typeof 123;//number
typeof true;//boolean

对于 引用类型 ,typeof运算符只能区分出 函数

1
2
3
4
typeof {};//object
typeof [];//object
typeof null;//object
typeof console.log;//function

变量计算-强制类型转换

  • 字符串拼接
  • ==运算符
  • if语句
  • 逻辑运算

字符串拼接

字符串拼接

==运算符

运算符前后的变量会先被强转为true/false再进行比较

  • 100被转换为字符串 再进行比较,所以相等
  • 0和””都被转换为false 再进行比较,所以相等
  • null和undefined都被转换为false 再进行比较,所以相等
    `==`运算符

if语句

变量做判断条件 时会先 强制转换 为boolean类型再判断
`if`语句


逻辑运算

首先要明确,逻辑与&&与逻辑或||返回的都是表达式,非!返回的是布尔值。

帮助理解

返回表达式的原则:从前往后判断,只要到了能判断出 整个表达式的真假 的位置我们就停下来返回这个位置的部分表达式。

&&:前后都为真才是真,只要有一个是假的就是假。所以只要有第一个表达式是假的我们就不用继续判断了,返回第一个表达式。如果第一个表达式是真的我们就继续判断第二个表达式,(但由于一定要返回一个表达式,所以)此时无论真假都得返回第二个表达式。

||:只要有一个是真就是真。所以只要有第一个表达式是真的就可以判断整个表达式都是真的,故返回第一个表达式。如果第一个表达式是假的那我们就要继续判断第二个表达式,(但由于一定要返回一个表达式,所以)此时无论真假都得返回第二个表达式。

例子

1
2
3
console.log(10 && 0);//0
console.log("" || "abc");//"abc"
console.log(!window.abc);//true

可以使用!!判断一个变量会被当做true还是false

1
2
var a = 100
console.log(!!a);//true

题目解答

JS中使用typeof能得到的哪些类型

6种,number、undefined、string、boolean、object、function
可以准确判断4种 值类型 ,但是 引用类型 中只能判断函数,其余的 数组、对象、正则、日期 都被识别为object

注意:null(空指针)也被识别为object!


何时使用===何时使用==

只有一种情况使用双等号==,其他时候全部使用三等号===
何时使用`==`
此时第三行代码相当于第四行代码的
简写
,这是jquery的源码推荐写法


JS中有哪些内置函数

内置函数(数据封装类对象):
ObjectArrayBooleanNumberStringFunctionDateRegExpError


JS变量 按 存储方式 分为哪些类型,有何特点

按照存储方式区分为:值类型、引用类型
特点:值类型相当于复制,引用类型则是 指针复制 并不是真正的拷贝,两个变量会共用同一个属性,他们的值的修改是相互干预的。
按存储方式区分JS变量


如何理解JSON

JSON是一种数据格式但从JS来看JSON就是一个JS内置对象,他有两个方法,“JavaScript Object Notation” 即 “JavaScript 对象表示法”,它是存储和交换文本信息的语法
JSON
stringify()把对象变成字符串
parse()把字符串变成对象


手写深拷贝

  • 注意判断值类型和引用类型
  • 注意判断是数组还是对象(判断对象自身属性)
  • 递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 深拷贝方法1
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj) {
// 如遇值类型则直接返回,否则继续执行【注意Object有引号】
if (typeof obj !== "object" || obj === null) {
return obj;
}

// 初始化返回结果
let cloneObj = Array.isArray(obj) ? [] : {};

// 遍历对象属性/数组元素
for (key in obj) {
// 筛选对象自身属性
if (obj.hasOwnProperty(key)) {
// 递归调用deepClone(),
cloneObj[key] = deepClone(obj[key])
}
}

// 返回结果
return cloneObj;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 深拷贝方法2
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj){
// 根据传入的参数obj判断拷贝数组还是对象
let objClone = Array.isArray(obj)?[]:{};
// 判断参数obj是否是引用类型(数组/对象)【注意Object有引号】
if(obj && typeof obj==="object"){
// 是对象则用for in遍历 对象属性
for(key in obj){
// 如果是非继承属性
if(obj.hasOwnProperty(key)){
//判断ojb子元素(数组元素/对象属性)是否为引用类型(数组、对象、函数)
if(obj[key]&&typeof obj[key] ==="object"){
//是则递归复制
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[0, 1, null, [1, 2], { name: "a" }, function a() { return 1; }],
b=deepClone(a);
b[3][0] = 5;
console.log(a,b);