一、基础数据类型
值类型
保存在栈内存中, 占用空间小, 大小固定. 通过按值来访问, 属于比较常使用的数据
目前常见的有6种:
- String
- Number
- Boolean
- Null
- Undefined
- Symbol
引用数据类型
保存在堆内存中, 占用空间大, 大小不固定. 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址, 查找数据的时候, 会先检索其在栈中的地址, 在根据其地址去堆种获取实体数据
- Object
- Array
- Function
- Date
- RegExp
- ...
Undefined和Null的纠葛
在 javascript中,将一个变量赋值给undefined或null, 几乎没有区别, 甚至在条件判断、相等运算符的使用中,甚至可以直接报告两者相等
var a = undefined ;
var b = null;
if(!a){
console.log('undefined is false');
}
if(!b){
console.log('null is false');
}
if (a == b){
console.log('undefined == null'); // true
}
其实这是由JavaScript最初设计的历史原因所造成的:
null: 表示一个“无”的对象, 转为数值为0
undefined: 表示一个“无”的数据, 即未被定义的数据, 转化数值为NaN;
- Null使用场景
1. 作为函数的参数, 表示该函数参数不是对象
2. 作为原型链上的终点
- Undefined使用场景
1. 变量被声明了,但没有赋值,则为undefined
2. 调用函数时, 需要传递的参数没有传递,则该参数为undefined
3. 对象中没有赋值的属性, 则其属性的值为undefined
4. 函数没有返回值时, 默认返回undefined
二、数据提升
提升概念
JavaScript代码在执行前引擎会先进行预编译, 预编译期间会将变量声明和函数声明提升至其对应作用域的最顶端
console.log(a);
var a = 1;
//预编译后的代码结构如下:
var a; //将变量a的声明提升至最顶端,赋值逻辑不提升
console.log(a); // undefined
a = 1; // 代码执行到原位置即执行赋值逻辑
变量提升
变量声明的提升会以变量所处的第一作用域为单位,即全局作用域中的声明的变量会提升至全局最顶层, 函数内声明的变量只会提升至该函数作用域最顶层
如下:
var a;
console.log(a); //输出undefined
a = 'a'
function test () {
var a; // 全局变量会被局部作用域中的同名变量覆盖
console.log(a); // undefined
a = 'a1'
}
test();
在ES6中新增了let和const关键字, 这也使js中存在了块级作用域, 会形成暂时性死区, 所以let和const声明的变量和函数是不存在提升现象的.
函数提升
和变量提升相比, 函数提升在作用域提升方面并无太大区别,只是函数提升只会提 升函数声明,而不会提升函数表达式
如下
console.log(foo1); //输出函数对象[Function:foo1]
foo1(); // 输出foo1 invoked
function foo1(){
console.log('foo1 invoked');
}
console.log(foo2); //输出undefiend
foo2(); // TypeError : foo2 is not a function
var foo2 = function(){
console.log('foo2 invoked');
}
三、类型检测
typeOf
1. 识别所有值类型
2. 识别函数
3. 判断是否是引用类型,但无法再继续细分
如下:
var a = 'str'; // typeOf a === 'string'
var a = 1; // typeOf a === 'number'
var a = true; // typeOf a === 'boolen'
var a = Symbol('s'); // typeOf a === 'symbol'
var a; // typeOf a === 'undefined'
var a = null // typeOf a === 'object'
var a = [1,2] // typeOf a === 'object'
var a = {name:'xiaolou'} // typeOf a === 'object'
var a = function(){ } // typeOf a === 'function'
instanceof
1. 区分引用类型
如下:
var a = [1,2] // a instanceof Array ->true
var a = {name:'xiaolou'} // a instanceof Object ->true
var a = function(){ } // a instanceof Function ->true
四、变量计算--强制类型转换
字符串拼接
var a = 100 + 10 //100
var b = 100 + '10' //1001
var c = '10' + true //'10true'
==运算符
100 == '100' //true
0 == '' //true
null == undefined //true
truely和falsely变量
truely变量: !!a === true的变量
falsely变量: !!a === false的变量
// 以下都是falsely变量,除此之外都是truely变量
!!0 === false;
!!NaN === false;
!!'' === false;
!!null === false;
!!undefined === false;
!!false === false;
if语句
var a = true
if(a){}
var b = 100
if(b){} // 把数字转换为true
var c = ''
if(c){} // 把空字符串转换为false
逻辑运算 &&、||、!
console.log(10&&0); // 0 把10转换成true
console.log('' || 'abc'); // 'abc' 把空字符串转换为false
console.log(!window.abc); //true window.abc是undefined 把非undefined转换成true
五、深拷贝
手写deepClone
//递归方式手写一个深拷贝
function deepClone(obj){
if (typeof obj !== 'object' || obj == null) {
return obj;
}
//初始化默认值
let result = obj instanceof Array ? [] : {};
for (let key in obj) {
//保障key不是obj原型上的属性
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}
Object.assign
Object.assign 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
var a = {name:'chonglou'};
var b = Object.assign({},a);
console.log(b);
b.name = 'xiaoming';
console.log('a',a);
console.log('b',b);
//输出 a: {name:'chonglou'} b:{name:'xiaoming'}
var a = {name:'chonglou',city:{address:'广州'}};
var b = Object.assign({},a);
console.log(b);
b.name ='xiaoming';
b.city.address = '深圳';
console.log('a',a);
console.log('b',b);
//输出: 可以看到深层次是浅拷贝
//a : {name:'chonglou',city:{address:'深圳'}};
//b : {name:'xiaoming',city:{address:'深圳'}};
JSON.stringify 和 JSON.parse
用 JSON.stringify 把对象转换成json字符串,再用 JSON.parse 把字符串转换成新的对象。
var a = {name:'chonglou'}
var jsonData = JSON.stringify(a);
var b = JSON.parse(jsonData);
b.name = 'xiaoming';
console.log('a',a);
console.log('b',b);
//输出 a: {name:'chonglou'} b:{name:'xiaoming'}
六、数据类型的常用操作
字符串
- 字符查找
charAt
根据索引查找字符,如果没有则返回空字符串
var a = 'string';
var res = a.charAt(0); // -> 's'
var res1 = a[0]; // -> 's'
var res2 = a.charAt(100); // -> ''
var res3 = a[100]; // -> undefined
//charAt索引过大或过小时返回空字符串,str[索引]返回undefined
charCodeAt
根据索引查找对应的ASCII码值,如果没有则返回空字符串
var a = 'zhangsan';
var res = a.charCodeAt(0); // -> 122 对应字母z
var str = String.fromCharCode(res); // -> 'z'
- 字符截取
substr(start,length)
1. start 必需,指定子字符开始的位置,length 可选,要截取的字符长度.
2. 当start为负数时,会从末尾开始查找并返回start数据长度,当len为负数时,会返回空字符串
let str = 'haohaoxuexitiantianxiangshang';
str.substr(3,6); // -> haoxue
str.substr(3); // -> haoxuexitiantianxiangshang
str.substr(-4); // -> hang
substring(start,end)
1. start 必需,指定子字符开始的位置, end 结束的字符下索引(不包含当前字符). end小于start, 会反过来end作为起点
let str = 'haohaoxuexitiantianxiangshang';
str.substring(3,6); // -> hao
str.substring(3); // -> haoxuexitiantianxiangshang
str.substring(10,3); // -> haoxuex
slice(start,end)
1. start 必需,指定子字符开始的位置, end 结束的字符下索引(不包含当前字符). 如果都为负数,会从末尾开始查找
2. start大于end, 则返回空字符串
let str = 'haohaoxuexitiantianxiangshang';
str.slice(3,6); // -> hao
str.slice(3); // -> haoxuexitiantianxiangshang
str.slice(-3,-1); // -> an
- 检测数据是否包含
indexOf
功能:从字符串首部开始搜索给定的字符,返回子字符串的位置,如果找不到该字符,则返回-1
let str = 'haohaoxuexitiantianxiangshang';
str.indexOf('haohao') > -1 // true
lastIndexOf
功能:从字符串尾部开始搜索给定的字符,返回子字符串的位置,如果找不到该字符,则返回-1
let str = 'haohaoxuexitiantianxiangshang';
str.lastIndexOf('shang') > -1 // true
includes
功能:检测当前字符串中是否包含某个字符, 返回true或者false
let str = 'haohaoxuexitiantianxiangshang';
str.includes('shang') // true
- 大小写转换
toUpperCase
//全部大写
let str = 'chong'
str.toUpperCase() // 'CHONG'
//首字母大写
str.substr(0,1).toUpperCase() + str.substr(1) // 'Chong'
toLowerCase
//全部小写
let str = 'CHONG'
str.toLowerCase() // 'chong'
- 分割成数组
split
功能:根据分割符来分割字符,如果没有分割符,则按字符串分割
let str = 'str|arr|object|func';
str.split('|'); //输出 [str,arr,object,func]
- 字符替换*
replace
功能:把指定的字符替换成别的字符
let str = 'str|arr|object|func';
str.replace('|','-'); //输出 str-arr-object-func
数组
- 基础使用
push
功能:向数组尾部追加数据
let arr = [1,2,3]
arr.push(4); //输出 [1,2,3,4]
pop
功能:从数组尾部删除数据
let arr = [1,2,3]
arr.pop(); //输出 [1,2]
unshift
功能:向数组开头追加数据
let arr = [1,2,3]
arr.unshift(4); //输出 [4,1,2,3]
shift
功能:删除数组的开头元素
let arr = [1,2,3]
arr.shift(); //输出 [2,3]
splice
功能:实现数组的增加、删除、修改,修改后的新数组
let arr = [1,2,3]
//增加 : arr.splice(n,0,x);在索引n的前面添加了x元素;
arr.splice(1,0,4) // -> [1,4,2,3]
//删除 :
//清空数组: arr.splice(0); // []
//从下标开始删除多少长度的数据: arr.splice(1,2); // 原数组[1]
//修改
//从下标开始删除多少长度的数据并增加: arr.splice(1,2,4); //原数组 [1,4]
- 查询和拼接
slice
功能:实现数组的查询, slice(start,end). 从下标start开始查找,到end结束(不包含end对应元素),start<end
let arr = [1,2,3,4,5]
arr.slice(1,3); // [2,3]
arr.slice(0)//[1,2,3,4,5] end没有写,则查找至末尾
//都为负数 ,从尾部查找
arr.slice(-2); // [2]
//如果都是小数, 会直接取整
let arr = [1,2,3,6,6,4]
arr.slice(1.3,4.2);//==> [2, 3, 6]
//如果是非有效数字:会先基于Number转换为数字,在进行截取
let arr = [1,2,3,6,6,4]
arr.slice("sss","sss");//==> []
arr.slice("1","3");//==> [2, 3]
//start 大于 end
let arr = [1,2,3,6,6,4]
arr.slice(4,2);//==> []
concat
功能:实现数组的合并,
let arr = [1,2,3]
let arr1 = [4,5]
arr.concat(arr1) // [1,2,3,4,5]
- 检测包含数据
indexOf
功能: 从数组的开头开始向后查找,查找不到时,返回-1
let arr = [10,20,30,10,20,30];
ary.indexOf(20) ;//==>1
lastIndexOf
功能: 从数组的尾部开始向前查找,查找不到时,返回-1
let arr = [10,20,30,10,20,30];
ary.indexOf(20) ;//==>1
includes
功能: 检测当前数组是否包含某项
let arr = [10,20,30,10,20,30];
ary.includes(20) ;//==>true
filter
功能: 过滤符合条件的数据, 并返回一个新数组
let arr = [10,20,30,10,20,30];
let temp = arr.filter(item => {
return item === 20;
})
//输出 temp : [20,20]
find
功能: 符合条件的第一个元素,如果没有符合条件的元素则返回undefined
let arr = [10,20,30,10,20,30];
let temp = arr.find(item => {
return item === 20;
})
//输出 temp :20
findIndex
功能: 符合条件的第一个元素索引,如果没有符合条件的元素则返回-1
let arr = [10,20,30,10,20,30];
let index = arr.findIndex(item => {
return item === 20;
})
//输出 index :1
- 转化成字符串
toString
功能: 把数组转换为字符串,转换后的字符串,每一项用逗号分隔
let arr = [1,2,3,4,5];
let res = arr.toString();
//输出 res: '1,2,3,4,5'
join
功能: 按指定的字符把数组转换为字符串
let arr = [1,2,3,4,5];
let res = arr.join('-');
//输出 res: '1-2-3-4-5'
- 排序或排列
reverse
功能: 把数组倒过来排列,返回排序后的新数组
let arr = [1,2,3,4,5];
arr.reverse()
//反序输出 arr = [5,4,3,2,1];
sort
功能: 把数组按大小顺序排列,返回排序后的新数组
let arr = [1,2,3,4,5];
arr.sort((a,b) => { b - a})
//降序输出 arr = [5,4,3,2,1];
- 遍历和映射
forEach
功能: 每个数组元素执行相同操作,返回执行后的新数组
let arr = [10,20,30,10,20,30];
arr.forEach(item => {
item += 1
})
//输出 arr = [11,21,31,11,21,31];
map
功能: 每个数组元素执行相同操作,返回执行后的新数组
let arr = [10,20,30,10,20,30];
let temp = arr.findIndex(item => {
return {
age:item
}
})
//输出 temp = [{age:10},{age:20},{age:30},{age:10},{age:20},{age:30}]