js基础知识梳理-数据类型以及实际应用场景

一、类型判断

1.1、数据类型介绍

五种简单数据类型:Undefined Null Boolean Number  String
一种复杂数据类型:Object
console.log( typeof undefined, typeof true, typeof 1, typeof '1', typeof {}, typeof null
 

Boolean类型转换规则:

 

Number类型基于IEEE754格式来表示整数和浮点数值

浮点数

数值范围

Number.MIN_VALUE 大多数浏览器中5e-324
Number.MAX_VALUE 大多数浏览器中1.7976931348623157e+308
超出范围自动转换为正负infinity

NaN

即非数值(not a number)是一个特殊的数值,用于标水一个本来返回数值的操作数为返回数值的情况(这样就不会抛错误了)
ECMAScript5中,任何数值除以非数值会返回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]

数值转换

 
3个函数可以吧非数值转换为数值:
用于任何数据类型:Number()、
专门用于字符串转换为数值:parseInt()和parseFloat()
Number()函数转换规则:
1、Boolean值true和false将分别转换1和0
2、如果是数字只是简单的传入和返回
3、如果是null值,返回0
4、如果返回undefined,返回NaN
5、如果是字符串,遵循一下规则:
如果字符串只包含数字(包括正负号)则将其转换为十进制即“1”会变成1,“123”会变成123,
而“011”会变成11(注意:前面0被忽略)
如果字符串只包含浮点数如“1.1”同上,0也会被忽略
如果字符串包含有效的十六进制格式,例如“0xf”则将其转换相同的大小的十进制整数值;
如果字符串是空的(不包含任何字符),则将其转换为0;
如果字符串包含除上述格式之外的字符。则将其转为NaN。
如果是对象则调用对象的value()的方法,然后依照前面的规则转换返回的值。如果转换的结果是
NaN,则调用对象的toString()方法,然后再将其依照前面的规则转换返回字符值。
  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 类型

创建:
var o = new Object()
Object 每个实例都具有下列属性和方法:
constructor: 保存用于创建当前对象的函数。
hasOwnProperty(propertyName):用于检查给定的属性在当前的对象实例中(而不是实例的原型中)
isPrototypeOf(object): 用于检查传入的对象是否是当前的对象的原型
propertyIsEnumerable(propertyName)用于检查给定的属性是否能够使用for-in语句
toLocalString():返回对象的字符串表示,该字符串与执行环境的地区对应
toString(): 返回对象是字符串表示
valueOf(): 返回对象的字符串,数值,或布尔值表示。通常与toString()方法的返回值相同
 

出个小题,说说下面类型是什么?

出个小题,说说下面类型是什么?
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

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
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方法判断数组

用Array对象的isArray方法判断const a = []; 最靠谱
const b = {};
Array.isArray(a);//true
Array.isArray(b);//false

 

二、类型的应用场景:

数据类型判断每时每刻都在用,下面只是举个拷贝的例子加深理解

需要知道的就是一点:JavaScript的数据类型分为基本数据类型和引用数据类型。

引用数据类型而言的拷贝地址就是浅拷贝,一行具体拷贝引用的值叫深拷贝(基本数据类型的值和引用数据类型的地址存放在栈内, 指向堆(存放引用数据具体的值) )

2.1、浅拷贝:

//  浅拷贝的意思就是只复制引用,而未复制真正的值。
const originArr = ['h', 'e', 'l', 'l','o'];
const originObj = {a:'w',b:'o',c:[1,2,3],d:{dd:'r'}};

const cloneArr = originArr;
const cloneObj = originObj;

console.log(cloneArr); 
console.log(originObj); 
 

//操作clone之后的值
cloneArr.push(1);
cloneObj.a = {aa:'ww'};

console.log(cloneArr); 
console.log(originArr); 

console.log(cloneObj); 
console.log(originArr); 

2.2、深拷贝

就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了。

修改修改之后的拷贝的值也不会影响原来的值

目前实现深拷贝的方法不多,主要是两种:

  1. 利用 JSON 对象中的 parse 和 stringify
  2. 利用递归来实现每一层都重新创建对象并赋值
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和++相关的知识补充,字太多了放两张图吧

 

 
待更新
posted @ 2020-11-05 00:17  pikachuWorld  阅读(314)  评论(0编辑  收藏  举报