js基础知识梳理-数据类型以及实际应用场景
一、类型判断
1.1、数据类型介绍
console.log( typeof undefined, typeof true, typeof 1, typeof '1', typeof {}, typeof null
Boolean类型转换规则:
Number类型基于IEEE754格式来表示整数和浮点数值
浮点数
数值范围
NaN
console.log(NaN==NaN) //false console.log(isNaN(NaN),isNaN("bule"))//true console.log(isNaN(10),isNaN("10"),isNaN("10"))//false[数字10,转换为数字10,转换为1]
数值转换
console.log(Number("Hello world")) console.log(Number("")) console.log(Number("000011")) console.log(Number(true))
parseInt()转换空字符串返回NaN(Number()则返回0) parseInt转换规则: var num1=parseInt("123blue") // 123 var num2=parseInt("") // NaN var num3=parseInt("0xA") // 10(十六进制) var num4=parseInt("22.5") // 22 var num5=parseInt("070") // 56(八进制) var num6=parseInt("70") // 70(十进制) var num7=parseInt("0xf") // 15(十六进制) //指定基数为16作为第二个参数 var num =parseInt("oxAF", 16) //175
String类型
1.字符字面量 2.字符串的特点不可变 3、转换为字符串 var age = 11; var ageStr = age.toString() // 字符串"11" var found = true var foundStr = found.toString()// 字符串"true" var num = 10; console.log(num.toString()) // "10" console.log(num.toString(2)) // "1010" console.log(num.toString(8)) // "12" console.log(num.toString(10)) // "10" console.log(num.toString(16)) // "a"
Object 类型
出个小题,说说下面类型是什么?
出个小题,说说下面类型是什么? function fun1(){}; const fun2 = function(){}; const fun3 = new Function('name','console.log(name)'); const obj1 = {}; const obj2 = new Object(); const obj3 = new fun1(); const obj4 = new new Function();
答案:
console.log(typeof Object);//function console.log(typeof Function);//function console.log(typeof fun1);//function console.log(typeof fun2);//function console.log(typeof fun3);//function console.log(typeof obj1);//object console.log(typeof obj2);//object console.log(typeof obj3);//object console.log(typeof obj4);//object
1.2、判断数据类型的方法
1.2.1、typeof
typeof基本数据类型,object不能精确判断
1.2.2、Object.prototype.toString.call(x) === '[object Object]'
console.log( Object.prototype.toString.call({})) console.log( Object.prototype.toString.call(null)) console.log( Object.prototype.toString.call([])) console.log( Object.prototype.toString.call('string')) console.log( Object.prototype.toString.call(1)) console.log( Object.prototype.toString.call(undefined)) console.log( Object.prototype.toString.call(true)) console.log( Object.prototype.toString.call({}).slice(8, -1)) console.log( Object.prototype.toString.call(null).slice(8, -1)) console.log( Object.prototype.toString.call([]).slice(8, -1)) console.log( Object.prototype.toString.call('string').slice(8, -1)) console.log( Object.prototype.toString.call(1).slice(8, -1)) console.log( Object.prototype.toString.call(undefined).slice(8, -1)) console.log( Object.prototype.toString.call(true).slice(8, -1))
1.2.3、instanceof
function Car(make, model, year) { this.make = make; this.model = model; this.year = year; } const auto = new Car('Honda', 'Accord', 1998); console.log(auto instanceof Car); // expected output: true console.log(auto instanceof Object); // expected output: true
const a = []; const b = {}; console.log(typeof a, '--', typeof b, '--', typeof c) console.log(a instanceof Array);//true console.log(a instanceof Object);//true 在数组的原型链上也能找到Object构造函数 console.log(b instanceof Array);//false
1.2.4、 用constructor判断
const a = {}; console.log('{} ', a.constructor);//function Object(){ [native code] } const b = /^[0-9]$/; console.log('/^[0-9]$/ ', b.constructor);//function RegExp() { [native code] } const c = []; // ƒ Array() { [native code] } console.log('[] ', c.constructor); console.log(c.constructor == Array);//true const d = null; console.log('null ', d.constructor);//报错
注意 : 前提是constructor属性小心不要改成了其他的类型,判断会错误
但是我实际运行了一下好像也没问题,这里记录下
//定义一个数组 const a = []; //将constructor属性改成了别的 应该下面的 a.contrtuctor = Object; console.log('1--', a.constructor == Array);//false console.log('2--', a.constructor == Object);//true console.log('3--', a instanceof Array);//true 可以正确判断
但是运行一下好像也没问题
1.2.5. isArray方法判断数组
const b = {}; Array.isArray(a);//true Array.isArray(b);//false
二、类型的应用场景:
数据类型判断每时每刻都在用,下面只是举个拷贝的例子加深理解
需要知道的就是一点:JavaScript的数据类型分为基本数据类型和引用数据类型。
引用数据类型而言的拷贝地址就是浅拷贝,一行具体拷贝引用的值叫深拷贝(基本数据类型的值和引用数据类型的地址存放在栈内, 指向堆(存放引用数据具体的值) )
2.1、浅拷贝:
// 浅拷贝的意思就是只复制引用,而未复制真正的值。
//操作clone之后的值 cloneArr.push(1); cloneObj.a = {aa:'ww'}; console.log(cloneArr); console.log(originArr); console.log(cloneObj); console.log(originArr);
2.2、深拷贝
就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了。
修改修改之后的拷贝的值也不会影响原来的值
目前实现深拷贝的方法不多,主要是两种:
- 利用
JSON
对象中的parse
和stringify
- 利用递归来实现每一层都重新创建对象并赋值
const originObj = {a:'w',b:'o',c:[1,2,3],d:{dd:'r'}}; const cloneObj = JSON.parse(JSON.stringify(originObj)); console.log(cloneObj === originObj); cloneObj.a = 'min'; cloneObj.c = [8,8,8]; cloneObj.d.dd = 'iphone'; console.log(cloneObj); console.log(originObj);
// 但是这个 方法有一个缺陷就是undefined、function、symbol 会在转换过程中被忽略 const originObj = { name:'iphoneX', a: undefined, b: Symbol(''), sayHello:function(){ console.log('Hello World'); } } console.log(originObj); const cloneObj = JSON.parse(JSON.stringify(originObj)); console.log(cloneObj);
//JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。 console.log(JSON.stringify({ x: 5, y: 6 })); // expected output: "{"x":5,"y":6}" console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)])); // expected output: "[3,"false",false]" console.log(JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] })); // expected output: "{"x":[10,null,null,null]}" console.log(JSON.stringify(new Date(2006, 0, 2, 15, 4, 5))); // expected output: ""2006-01-02T15:04:05.000Z"" const bb = JSON.stringify( { x: 10, y: undefined, z: function(){}, w:Symbol('') } ) console.log(bb);
最后一个例子JSON.stringify 方法有一个缺陷就是undefined、function、symbol 会在转换过程中被忽略
深拷贝:
关于constructor查看
function deepClone(source){ console.log('source-->', source, 'source.constructor-->', source.constructor) const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象 for(let keys in source){ // 遍历目标 console.log('@@', keys, source, typeof source[keys], source[keys], source.hasOwnProperty(keys)) if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下 console.log(source[keys].constructor) targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ // 如果不是,就直接赋值 targetObj[keys] = source[keys]; } } } return targetObj; }
javaScript 中数组和对象自带的拷贝方法都是“首层浅拷贝"
我们知道在 JavaScript
中,数组有两个方法 concat
和 slice
是可以实现对原数组的拷贝的,这两个方法都不会修改原数组,而是返回一个修改后的新数组。
同时,ES6 中 引入了 Object.assgn
方法和 ...
展开运算符也能实现对对象的拷贝。
concat
只是对数组的第一层进行深拷贝, slice
只是对数组的第一层进行深拷贝,实现的是对象第一层的深拷贝。Object.assign()
拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值后面的只是拷贝的引用值。
2.3遇到有意思的一道面试题
问怎么样才能打印log,输出1呢
if(a==1&&a==2&&a==3) console.log(1)
// 实现方式
var a = { // a是一个对象 value: 0, toString() { return ++this.value // } } // 打印数据: console.log(typeof a,'11aa-->', a, a==1&&a==2&&a==3) // this.value++ false if(a==1&&a==2&&a==3) console.log(1) // 每次==做比较a都会自增1
打印结果:
// 实现方式 var a = { // a是一个对象 value: 0, toString() { return ++this.value // } } // 打印数据: console.log(typeof a,'11aa-->', a) if(a==1&&a==2&&a==3) console.log(1) // 每次==做比较a都会自增1
可以看到log打印出1, 只有每次==比较就会隐士调用toString方法自增1
回去专门查啦objec和++相关的知识补充,字太多了放两张图吧