关于Javascript的数据类型、变量定义、隐式转换

Javascript数据类型、变量定义、隐式转换、数据操作

1、js数据类型

五种简单数据类型

number、string、boolean、undefined、null

一种复杂数据类型

object  包括数组,function,Date

(数组实际上是对象的一种特殊模式,只不过索引正好是整数)

其中number里有一种特殊数据 NaN。

如何区分数据类型?typeof() 和 a instanceof 数据类型

typeof返回的数据类型有

number 数字 string 字符串 boolean 布尔 undefined 定义未初始化  
object 对象(null) function 函数
注意:null也是返回object

typeof原理:

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息
000:对象
010:浮点数
100:字符串
110:布尔
1:整数
null:所有机器码均为0
undefined:用 −2^30 整数来表示

所以null会被判定为对象

还有一个不错的判断类型的方法,就是Object.prototype.toString

Object.prototype.toString.call(1) // "[object Number]"
Object.prototype.toString.call('hi') // "[object String]"
Object.prototype.toString.call({a:'hi'}) // "[object Object]"
Object.prototype.toString.call([1,'a']) // "[object Array]"
Object.prototype.toString.call(true) // "[object Boolean]"
Object.prototype.toString.call(() => {}) // "[object Function]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call(Symbol(1)) // "[object Symbol]"

既然数组也是对象的一组,如何区分呢?**instanceof **

var ss = [1,2,3];
ss instanceof Object	//返回true
ss instanceof Array		//返回true

Instanceof 原理

function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}
只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false

instanceof扩展
释意:检测一个构造函数的原型属性所指向的对象是否存在于另一个要检测的对象的原型链上。
function Persion(){};
var persion = new Persion();
console.log(persion instanceof Persion);

null 和undefined、NAN 的区别

undefined 是指var声明变量 但是未对其加以初始化
null 	  是指一个空对象指针,这也是为什么typeOf(null)返回object
NaN		  非数值,表示本来要返回数值的操作未返回数值

undefined 是指定义的变量没有初始化 var a;console.log("a",a) = undefined
null 是指空对象,typeof(null) = "object"

简单和复杂数据类型的存储

基本类型他们占据的空间是固定的,所以把它们存储在栈中,栈按照后进先出的原则存储数据。 

引用类型它们的大小是不固定的,所以不能存储在栈区,而是分配到堆区,堆区是内存中的动态区域,程序运行的时候动态分配给代码和堆栈,虽然这些数据大小不固定,但是地址的大小是固定的,所以我们在栈区存储对象在堆区的地址即可。这个地址即指针。

由于js数据类型有两种,所以数据拷贝的时候会涉及浅拷贝和深拷贝两种

2、定义变量的几种方法

var let const 和全局变量

1、var 和 let的区别

es6之前,我们定义变量使用var,let的作用域比var更严格。

var a = [];
for(var i=0;i<10;i++) { 
    a[i] = function(){
        console.log(i);
    };
} 
a[6]();
var a = [];
for(let i=0;i<10;i++) { 
    a[i] = function(){
        console.log(i);
    };
} 
a[6]();

由于js不存在块级定义域,所以第一个i溢出。而使用let定义变量,会有一个块级作用域的 概念,每次调用的时候let都是新的。

2、const定义不可改变的常量。

const pie = 3.1415926;

3、全局变量

test = 222; //直接定义的就是全局变量

3.由var的作用域的思考

之前提到js作用域只有全局作用域和方法作用域,但是为什么var定义的变量能在函数外被访问到呢。 我们来看两个例子。

for(var i=0;i<3;i++) { 
	var k = i + 1;
} 
console.log(i,k);
function foo(){
	var a = 6;
	return a;
}
foo();
console.log(a);

为什么下面的a是undifind? 事实是:JavaScript以函数为界,每个函数内部拥有一个局部作用域;任何其他的块(包括普通代码块,for循环、if、while等代码块)不存在局部作用域,使用var声明的变量可以直接穿过这些代码块,可以被外部代码访问到。

4、隐式转换

1、运算符中的隐士转换

​ 基本数据类型:

​ 加号运算符有两个作用,字符串拼接和加法运算,所以 ​ 1、string和其他类型都会转为string进行字符串拼接。

​ 2、没有string类型,所有数据转换为number进行运算。

​ 减法运算符,所有的数据都会默认转为number类型进行运算。

​ 对象数据类型:

​ 会先调用valueOf() 方法

2、语句中的隐士转换

​ if(condition){}

​ 会调用Boolean(condition),把condition隐士转换为boolean类型。

3、运算符 == 和 ===

==

1、若类型不同,则按===规则判断

2、类型不同,则启用隐式类型转换

    有NAN,一律返回false
		有布尔类型,布尔类型转换成数字比较
		有string类型,两种情况: 1. 对象,对象用toString方法转换成string相比。2.数字,string类型转换成数字进行比较
		null和undefined不会相互转换,相等
		有数字类型,和对象相比,对象用valueof转换成原始值进行比较
		其他情况,一律返回false

===

1、类型不同,不等
2、null,undefined,boolean,number这四个类型的只要值(数值)相等,就相等,-0 === 0 //true
3、只要其中有一个为NAN,则不等
4、string类型,长度/内容/编码不同,都是不等,相同位置包含相同的16位,相等
5、指向相同的对象,数组,函数,则相等,若指向不同对象,不等

题型:

1 == "1"  true
1 == [1]  true
1 == false false
1 == true true

1 === "1"  false
1 === [1]  false
1 === true  false

null==undefined //true
null===undefined //false
NaN==NaN //false
NaN===NaN //false

var i = 1, j = new Number(i), k = Number(1) 
console.log(1 == j,i == k,i === j,i === k, i== k)

5、常见的数据操作

5.1数组操作

数组遍历 map(function(currentValue,index,array){}) 数据插入 push() unshift()

数组截取 slice() splice(index,howmany,item1……itemx)

连接多个数组 concat()方法 arrayObject.concat(arrayX,arrayX,……,arrayX)

数组去重如何实现

function unduplicat(array){

	var result = [];

	array.forEach(function(value){

		if(result.indexOf(value) < 0){

			result.push(value);

		}

	})

	return result;

}

数组扁平化如何实现

var result=[];
var arr=[1, [2, [ [3, 4], 5], 6]];

function flat(arr,result){
	for(var i=0;i<arr.length;i++){
    	if(typeof arr[i]==="number"){
        	result.push(arr[i]);
        }
        else{
        	flat(arr[i],result);
        }
    }
}
flat(arr,result);
console.log(result);
5.2 字符串操作

str.slice(start,end) str.subString(start,end)

str.replace(‘’,’’)

Str.indexOf(‘’)

Str.split(分隔符,howmany)

slice()和splice()的区别

slice()对字符串和数组都是截取,原有数组不会改变 splice()是对数组的截取,返回被截取的元素,原有数组会改变

字符串如何去掉空格

str = str.replace(/\s*/g,"");
\s	匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
*	匹配前面的子表达式零次或多次。
正则表达式后面的全局标记 g 指定将该表达式应用到输入字符串中能够查找到的尽可能多的匹配。
表达式的结尾处的不区分大小写 i 标记指定不区分大小写。

#####5.3 深拷贝与浅拷贝

关于深拷贝浅拷贝,之前有整理一篇文档,可以去看哦。