目录
JS的数据类型有8种,分别是Number,String,Null,Undefined,Boolean,Symbol,BigInt,Object,前面7种属于基本数据类型,而Object属于引用数据类型。
基本数据类型与引用数据类型的区别
(1)基本数据类型
基本数据类型的值存储在栈中 ,当申明了一个变量的时候,变量会去内存空间找对应的值,如果找到了对应的值,就直接把该值的内存地址存到变量里;如果没找到,就创建一个新的空间来存储对应的值,并且把新空间的内存地址存到变量里。js中,变量不存储任何值,而存储的是值的内存地址。基本数据类型一旦创建,就是不可变的,因为它占据的空间是固定的,修改变量的值相当于重新创建一个内存空间,变量指向内存空间的地址。
(2)引用数据类型
当一个对象被创建时,会在内存空间中开辟一个地址,所以,创建两个一样的对象不会相等,同理创建两个空对象也不会相同。
let obj = { name: 'niu', age: 12 } let obj2 = { name: 'niu', age: 12 } console.log(obj === obj2);//false
因为变量存储的是对象的地址,每创建一个对象,就会开辟一个新的空间,地址就是内存空间的位置0x22,0x23。当然,对象的属性所对应的值是基本数据类型,所以按照基本数据类型的值的存储方式存储。obj不等于obj2(地址不同)
图1-1
当let obj1 = obj时,相当于obj1直接指向obj对应的地址,所以当name属性改变时,不论obj还是obj1都会发生变化。
let obj = { name: 'niu', } let obj1 = obj obj1.name = '牛' console.log("obj",obj); console.log("obj1",obj1);
先让obj2 = obj,再让obj2={ }空对象,再obj2.name = "猪八戒",此时,因为obj2又重新创建了一个对象,所以obj2又开辟出一片新的内存地址,所以无论obj2的属性怎么变都不会影响到obj。再假设一种情况,先让obj2=obj,再让obj2=null,此时会是什么情况(null对象里什么都没有,也就是说null不会存储任何内存空间的地址,也就是obj2与obj断了联系,互不影响了)。
图1-2
let obj = { name: 'niu', } let obj1 = obj obj1 = null console.log('obj', obj); // obj {name: 'niu'} console.log('obj1', obj1); // obj1 null let obj = { name: '孙悟空', } let obj1 = obj obj1 = {} obj1.name = "猪八戒" console.log('obj', obj); //obj {name: '孙悟空'} console.log('obj1', obj1); //obj1 {name: '猪八戒'}
总结:a.修改对象,其他对象指向该对象,那么所有指向它的变量都将受影响,如图1-1(因为他们使用的是同一片内存空间)。b.修改变量,如图1-2,修改的是obj2,obj2={ },修改后重新开辟空间,所以之前的对象不受影响。
1.Number
- 在JS中所有的整数和浮点数都是Number类型
- JS中的数值并不是无限大的,当数值超过一定范围后会显示近似值
- 在JS中不能进行一些精度比较高的运算(二进制计算,转换后会不太准确)
- Infinity 是一个特殊的Number类型,表示无穷
- NaN 也是一个特殊的Number类型,表示非法的数值
Number的常用方法
- isInteger() 判断一个数是否是整数,返回布尔值
- isNaN() 判断一个数是否为NaN
- toFixed(x) 把一个数保留x位小数,且转化为字符串
- toString() 转化为字符串
console.log(Number.isInteger(34.345));//false console.log(Number.isInteger(34));//true console.log(isNaN(3));//false console.log(isNaN(3+'pw'));//true let num = 12.567 console.log(num.toFixed(2));//12.57 字符串类型 console.log(num.toFixed(1));//12.6 字符串类型 console.log(num.toString());//12.567 字符串类型
从字符串截取数字
- parseInt(string, radix) 截取整数 第一个参数表示要截取数字的字符串,第二个表示进制(可选,默认为10进制)
- parseFloat(string) 截取浮点数
当截取不成功时,会返回NaN,截取整数时,从头开始截取,遇到非数字则停止截取(小数点也要停止截取),截取浮点数时,遇到非数字停止截取。
console.log(parseInt('235ddfcv')); //235 console.log(parseInt('235d123')); //235 console.log(parseInt('23.5d123')); //23 console.log(parseInt('0.5d123')); //0 console.log(parseInt('d123')); //NaN console.log(parseInt('456d123',16)); //72798499 16进制 console.log(parseFloat('4.56d123')); //4.56 console.log(parseFloat('0.56d123')); //0.56
数学运算
- Math.abs() 求一个数的绝对值
- Math.min() 求多个值中的最小值
- Math.max()求多个值中的最大值
- Math.pow()求x的y次幂
- Math.sqrt() 求一个数的平方根
- Math.floor() 向下取整
- Math.ceil() 向上取整
- Math.round() 四舍五入取整
- Math.trunc() 直接去除小数位
- Math.random() 生成一个0-1之间的随机数
- Math.round(Math.random(y - x) + x) 生成一个x-y之间的随机整数
2.BigInt
BigInt是新加入的一个数据类型,大整数。Number类型只能安全的表示-(
-1)到
-1之间的整数,超出范围的整数都将失去精度,而BigInt支持更大范围的整数精度(大于
-1)。
创建BigInt有两种方式
(1)直接在数字后面加n
(2)BigInt(‘9007199254740995’)
console.log(typeof 9007199254740995n); //bigint console.log(BigInt('9007199254740995')); //9007199254740995n
3.String
\ 转义
\n 换行
\t 制表符
引号用法:外双内单,外单内双
字符串方法
1)字符串本质上是一个字符数组
'hello' --> ['h','e','l','l','o'],所以它可以用length获取长度,用[index]获取某个位置的字符
2)根据索引获取
str.at() //根据索引获取字符,可以传负数,负数是从右往左获取 str.charAt() //根据索引获取字符,不能用负数
3)拼接字符串
str.concat() //连接2或多个字符串 str.repeat(number) //传入一个数字,为重复拼接次数
4)查找字符串中有无某字符
str.includes(string,start) // 第一个参数表示要找的字符,第二个参数表示查找开始位置索引,找到了返回true, // 找不到返回false str.indexOf() // 传入字符,如果找到了返回第一个字符的索引,没找到返回-1 str.lastIndexOf() // 从后往前找,找到了返回第一个索引,找不到返回-1
5)检查字符串是否以指定内容开头和结尾
str.startsWith() // 字符串开头是否以指定内容开头,返回布尔值 str.endsWith() // 字符串是否以指定内容结尾,返回布尔值
6)添加指定内容使字符串保持一定长度
let str = 'hello' str.padStart(7,'0') // 字符串前面添加某字符到固定长度 // 第一个参数是字符串的长度,若原先的字符串长度不够,则在前面加上第二个参数 console.log(str.padStart(7,'0'));// 00hello str.padEnd(8,'1') // 在字符串的尾部补充到固定长度 console.log(str.padEnd(8,'1'));// hello111
7)字符串的替换
let str = 'hello hello hello' console.log(str.replace('hello','你好')); //你好 hello hello // 两个参数,第一个参数是被替换的字符,第二个是要替换的字符,只会替换一个 console.log(str.replaceAll('hello','你好')); //你好 你好 你好 // 和上面一样,但替换的是字符串中所有的字符
8)截取字符串
str.slice() // 两个参数,第一个是截取的开始位置索引,第二个是截取的结束位置索引,包含开始不包含结尾 str.substring() // 和slice一样,但传入参数的时候,它会自动调整两个参数的位置
9)字符串切分为数组
let str = 'hello' console.log(str.split(''));//['h', 'e', 'l', 'l', 'o'] let str2 = 'aaa$bbb$ccc$ddd' console.log(str2.split('$'));//['aaa', 'bbb', 'ccc', 'ddd']
10)转换大小写
let str = 'AABBccdd' str.toUpperCase()//转换为大写 console.log(str.toUpperCase());//AABBCCDD str.toLowerCase()//转换为小写 console.log(str.toLowerCase());//aabbccdd
11)去除空格
let str = ' abc ' console.log(str);//' abc ' // 去除前后空格 console.log(str.trim());//'abc' // 去除前面空格 console.log(str.trimStart());//'abc ' // 去除后面空格 console.log(str.trimEnd());//' abc'
4.Boolean
布尔值为下面的值时为false,其余情况都为true。
- 0
- null
- ""
- false
- undefined
- NaN
5.Null和Undefined
null
表示空对象,一般用于释放指向对象的引用地址。
undefined
申明了却没有赋值,变量就为undefined;调用函数时,应该提供的参数没有提供,该参数等于undefined;对象没有赋值的属性,该属性的值为undefined;函数没有返回值时,默认返回undefined。
6.Symbol
- symbol表示独一无二的值(两个看起来一样的symbol也不相等)
let a = Symbol('abc') let b = Symbol('abc') console.log(a === b); //false console.log(a == b); //false
- symbol作为对象属性名时需用[ ]表示,通过symbol创建的属性是不希望被外界访问的属性。
let obj = { name: "牛马", [Symbol('hhhhh')]: "90" } console.log(obj[Symbol('hhhhh')]); //undefined //这里访问对象用[]代替点,但是访问不到,因为Symbol('hhhhh')每次访问都是一个不一样的值 //所以需要存储Symbol('hhhhh')的值 //正确做法是 let age = Symbol('hhhhh') let obj = { name: "牛马", [age]: "90" } console.log(obj[age]); //90
- symbol不能做任何运算
let name = Symbol('name'); console.log(name + 111) //报错,不能进行运算
- symbol的遍历
let age = Symbol('hhhhh') let obj = { name: "牛马", [age]: "90" } // 遍历不到symbol for (let i in obj) { console.log(i); //name } // 可以遍历所有属性的key,放到数组 console.log(Reflect.ownKeys(obj)); //['name', Symbol(hhhhh)] // 遍历不到symbol的key console.log(Object.keys(obj));//['name'] // 只能遍历到symbol console.log(Object.getOwnPropertySymbols(obj));//[Symbol(hhhhh)] // 遍历不到symbol的key console.log(Object.getOwnPropertyNames(obj));//['name']
- symbol的方法
(1)symbol.for()
(2)symbole.keyFor()
// symbol.for()的值可以相等 let a = Symbol.for('cccc') let b = Symbol.for('cccc') console.log(a === b); //true // Symbol.keyFor()可以拿到symbol.for()括号里的值 let c = Symbol('dddd') console.log(Symbol.keyFor(a)); //cccc console.log(Symbol.keyFor(c)); //undefined
Symbol的作用
对象中有Symbol.iterator 这个属性的话,这个对象就可以被 for… of 遍历,否则遍历不了。
7.Object
创建对象
let obj = new Object()这里new可以省略
let obj = { }
let str = 'message' let obj = { name:'牛马', ["age"]:23, [Symbol('6')]:'abcd', [str]:'你好', method:{ name:'马' } }
访问对象可以用obj.propertyName,也可以用obj[propertyName],方括号中可以是字符串,变量,symbol。
检查对象中是否含有某属性
in操作符
“propertyName” in obj 如果有该属性则返回true,没有返回false
对象分类
1)内建对象 :Object,Function,Array,String,Number.......
//它们使用时需要new一下 let str = new String("hello") let str1 = "hello" //用new创建和用字面量创建是一样的 //除了新加入的Symbal和BigInt不支持用new创建,其他都支持,但通常都使用字面量创建
2)宿主对象 :Dom,Bom
3)自定义对象 :程序员自己写的对象
Object内置对象
1)Object.assign( target, ...source )
对象拷贝
可传入多个参数,第一个是目标对象,拷贝后所有属性和方法都会存到target里,后面的参数可以传多个对象,如果有相同的属性则看参数位置,哪个位置越靠后,就用哪个的属性。
let obj = {a:2} let obz = {b:3} let ob = Object.assign(obj, obz) console.log(ob, obj, obz); //{a: 2, b: 3} {a: 2, b: 3} {b: 3} // ob和obj是相同的 let obj2 = Object.assign({}, obj, obz, {c : '我是牛马'}) console.log(obj2); //{a: 2, b: 3, c: '我是牛马'} let obj3 = Object.assign({c: '你是牛马',a: 5}, obj, obz, {c: '我是牛马'}) console.log(obj3); //{c: '我是牛马', a: 2, b: 3}
2)Object.create( proto, propertiesObject )
创建对象
第一个参数为原型对象,是必传的参数,第二个参数是属性对象,也就是对象的属性是一个对象(如name:{ }),非必传参数。
// 只传入第一个参数,参数为null,创建的对象没有原型,是纯净对象 let c = Object.create(null) console.log('c', c); // 传入空对象 let d = Object.create({}) console.log('d', d); // 传入Object.prototype let e = Object.create(Object.prototype) console.log('e', e); /* 当然,你会发现控制台打印的d和e是一样的,也就是说这两种创建方式创建出的 对象都是原型里什么都没有的对象,但他们并不相等,因为内存地址不同 */ //传入对象{name:"张三",age:3} let f = Object.create({name:"张三",age:3}) console.log('f',f);
从代码和图片可以看出,当只传入一个参数时,创建的对象的参数会添加到原型上去,而创建的对象依旧为空,如果需要给这个空对象创建属性,则要传入第二个参数(属性对象)。
属性对象
形式:{ name: { }, age:{ } }
name,age对象中需要传的参数如下,它们以键值对形式传入
1)value 属性值,默认为undefined
2)configurable 当它的值为true是,属性才可以被删除或者属性名才可以被修改(如删除name属性,或者修改name为names),默认为false
3)enumerable 当它的值为true是,属性才可以被遍历(枚举),默认为false
4)writable 当它的值为true是,属性的值才可以被修改,默认为false,只读
5)get 属性的getter函数,当属性被访问时,函数执行,返回一个值为属性值,默认为undefined
6)set 属性的setter函数,当改变属性值时,函数执行,函数的参数为属性改变后的值,默认为undefined
*注意:value和writable出现时不能出现get和set,这两组不相容,因为get的返回值相当于value的值,set出现代表属性值一定是可以改变的。
let a = Object.create(Object.prototype,{ age:{ value:17, configurable:true, //可删除,可修改属性名 writable:true, // 可修改属性值 }, name:{ value:"孙悟空", enumerable:true // 可遍历 } }) // *尝试这四个方法的时候要注释调其他几个,以免相互受影响 // 1.控制台打印初始a console.log(a); //{name: '孙悟空', age: 17} // 2.删除两个属性后打印a,发现name属性不能被删除 delete a.age delete a.name console.log(a); //{name: '孙悟空'} // 3.修改两个属性的值,发现只有age被修改了 a.age = 100 a.name = "猪八戒" console.log(a); //{name: '孙悟空', age: 100} // 4.遍历属性,发现只能遍历到name for(let item in a){ console.log(item); //name }
用Object.create()创建的对象会有属性对象的约束,通过属性对选哪个的参数规定约束条件,而普通创建方式创建的对象没有约束。
3)Object.defineProperty( object, prop, descriptor)
监听对象属性(监听单个)
一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。也是vue2的双向数据绑定原理。需要传三个参数,第一个是需要新增或修改属性的对象;第二个是属性名,需用引号;第三个是属性描述。后面两个参数相当于把属性对象拆开了。
例子1:vue2双向绑定原理
<input type="text" id="input"> <h2 id="h2"></h2> <script> let input = document.getElementById('input') let h2 = document.getElementById('h2') let obj = { text: '', } Object.defineProperty(obj, "text", { get: function () { return h2.innerText }, //获取值(这里h2.innerText已经被dom获取了,所以get存在与否都行) set: function (newValue) { //设置值,监听属性变化 console.log(newValue); h2.innerText = newValue } }) input.addEventListener('input', function (e) { obj.text = e.target.value }) </script>
例子2:添加与修改对象属性
let o = {} // 添加 Object.defineProperty(o, "a", { value : 37, writable : true, enumerable : true, configurable : true }); console.log(o.a); //37 let bValue = 10 Object.defineProperty(o, "b", { get(){return bValue}, set(newValue){ bValue = newValue }, enumerable : true, configurable : true }); console.log(o.b); //10 // 修改 // 有set可以修改,当属性值发生变化时,操作值,通过get返回给属性,也就是监听属性值,如o.b // 有writable:true时也可以修改,如o.a // 通过直接赋值的属性也可以进行修改,如o.c o.b = 3 o.c = "你好" o.a = 0 o.c = "nihao" console.log(o.b,o.c,o.a); //3 nihao 0
4)Object.defineProperties( obj, propertiesObject )
显而易见,它是Object.defineProperty()的复数形式,就是监听多个属性的变化,第一个参数是被监听的对象,第二个参数是属性对象,里面可以有多个属性。用法和前面一样。
5)Object.keys( obj )
遍历对象的属性名
传入一个对象(也可以是字符串或者数组,但是在遍历字符串或数组的时候,索引就相当于属性名,而值就相当于属性值),遍历对象的属性名,返回一个属性名组成的数组,遍历不到Symbol()属性。
let obj = { a:1, b:2, c:3, [Symbol()]:4 } let result = Object.keys(obj) console.log(result);//['a', 'b', 'c']
6)Object.values( obj )
遍历对象的属性名
传入一个对象(也可以是字符串或者数组),遍历对象的属性值,返回一个属性值组成的数组,遍历不到Symbol()属性。
let obj = { a:1, b:2, c:3, [Symbol()]:4 } let result = Object.values(obj) console.log(result);//[1, 2, 3]
7)Object.entries( obj )
遍历对象的键值对
传入一个对象(也可以是字符串或者数组),遍历其键值对,返回一个数组,数组里是键值对形式的数组,遍历不到Symbol()属性。
let obj = { a:1, b:2, c:3, [Symbol()]:4 } let result = Object.entries(obj) console.log(result); // [['a', 1],['b', 2],['c', 3]] // 如果想单独拿到key或者value result.forEach(([key,value])=>{ console.log(key,value); // a 1, b 2, c 3 }) console.log(Object.entries(['e','f','g'])); //[['0', 'e'],['1', 'f'],['2', 'g']] console.log(Object.entries('efg')); //[['0', 'e'],['1', 'f'],['2', 'g']]
8)Object.freeze( obj )
冻结对象
传入的对象和返回的是同一个对象,但对其做了冻结:对象就再也不能被修改,也不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,该对象的原型也不能被修改。当然,数组也是对象,所以数组也可以被冻结,从而无法被修改。
let obj = { name: "孙悟空", age: 900, child:{ name: "孙猴" } } Object.freeze(obj) obj.name = "猪八戒" obj.age = 800 obj.child.name = "牛马" console.log(obj); //name: '孙悟空', age: 900, child: {name: '牛马'}
我们从代码中发现,当对象里还有对象时,里面的对象属性依然可以被修改,所以Object.freeze()为浅冻结,这点要注意。
9)Object.prototype.hasOwnProperty( )
原型方法,判断对象中是否有某属性,调用形式:obj.hasOwnProperty( "prop" )
第一个参数是对象,在前面,第二个参数是对象的属性,写的时候得用引号。只要属性存在(包括属性值是null,undefined),则返回true,不存在返回false。它和in操作符都是判断对象中是否存在某属性,不同的是in会在原型上找,而它不会。
let obj = { name: "nihao", xxx: null, yyy: undefined } console.log(obj.hasOwnProperty('name')); //true console.log(obj.hasOwnProperty('xxx')); //true console.log(obj.hasOwnProperty('yyy')); //true console.log(obj.hasOwnProperty('toString')); //false toString是原型上的方法
10)Object.is(value1, value2)
比较两个值是否为同一个值
传入两个参数,都是要比较的值,如果是同一个,返回true,否则返回false。如果满足以下任意条件则两个值相等:
- 都是 undefined
- 都是 null
- 都是true或都是false
- 都是相同长度、相同字符、按相同顺序排列的字符串
- 都是相同对象(意味着都是同一个对象的值引用)
- 都是数字且
- 都是 +0
- 都是 -0
- 都是 NaN
- 都是同一个值,非零且都不是 NaN
Object.is(),==,=== 三个都是判断是否相等,==会在类型不同的时候强制转换类型,再进行判断。用等号判断的时候,+0和-0是相等的,而Object.is()不相等;用等号判断NaN是不相等的,而Object.is()相等。
console.log(Object.is(NaN,NaN)); //true console.log(Object.is(null,null)); //true console.log(Object.is(undefined,undefined)); //true console.log(Object.is(+0,-0)); //false console.log(Object.is(0,-0)); //false console.log(NaN == NaN); //false console.log(NaN === NaN); //false console.log(+0 == -0); //true console.log(+0 === -0); //true console.log('' == false); //true
11)Object.getOwnPropertyNames(obj)
获取属性名
传入一个对象,返回自身可枚举和不可枚举的属性名组成的数组,但不包括symbol。
let arr = ["a", "b", "c"]; console.log(Object.getOwnPropertyNames(arr)) //['0', '1', '2', 'length'] //不可枚举属性 let obj = Object.create({}, { getFoo: { value: function() { return this.foo; }, enumerable: false //不可枚举,for...in...遍历不到 } }); obj.foo = 1; console.log(Object.getOwnPropertyNames(obj)); // ["foo", "getFoo"]
12)Object.getOwnPropertySymbols(obj)
获取symbol属性名
传入一个对象,只获取对象的symbol属性名,返回一个由symbol属性名组成的数组。
let obj = { [Symbol("a")]:666, [Symbol.for("b")]:888, c:999 } console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(a), Symbol(b)]
13)Object.prototype.isPrototypeOf( )
判断一个对象是否存在于另一个对象的原型链上
写法:prototypeObj.isPrototypeOf(object),参数object表示在该对象的原型链上搜寻,返回一个布尔值,prototypeObj如果为 undefined 或 null,会报错。
function Foo1() {} function Bar2() {} function Baz3() {} Bar2.prototype = Object.create(Foo1.prototype); Baz3.prototype = Object.create(Bar2.prototype); let baz3 = new Baz3(); console.log(Baz3.prototype.isPrototypeOf(baz3)); // true console.log(Bar2.prototype.isPrototypeOf(baz3)); // true console.log(Foo1.prototype.isPrototypeOf(baz3)); // true console.log(Object.prototype.isPrototypeOf(baz3)); // true 对象的原型链必有Object
14)Object.getPrototypeOf( )
返回指定对象的原型
Object.getPrototypeOf(object),传入一个object,返回其原型。
let proto = {}; let obj = Object.create(proto); Object.getPrototypeOf(obj) === proto; // true let reg = /a/; Object.getPrototypeOf(reg) === RegExp.prototype; // true let obj2 = new Object(); Object.prototype === Object.getPrototypeOf( obj2 );// true Object.prototype === Object.getPrototypeOf( {} );// true
JS类型判断
1)typeof
写法有两种,typeof( 表达式 )或者typeof 变量名
typeof的返回值为字符串,用typeof判断null和数组,new的对象,普通对象的时候返回'object',能判断出函数,返回'function'
console.log(typeof "niu");//string console.log(typeof("niu"));//string console.log(typeof "");//string console.log(typeof 345);//number console.log(typeof Infinity);//number console.log(typeof true);//boolean console.log(typeof Symbol('x'));//symbol console.log(typeof null);//object console.log(typeof sss);//undefined console.log(typeof undefined);//undefined console.log(typeof {});//object console.log(typeof []);//object console.log(typeof function(){});//function console.log(typeof new Map());//object
2)instanceof
写法是:a instanceof b
判断a是否为b的实例,返回一个boolean值,如果a是b的实例则返回true,反之。instanceof只能用来判断对象和函数,不能用来判断字符串和数字等基本数据类型。
往深了理解,instanceof用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上。object instanceof constructor,object是实例对象,constructor是构造函数。
let a = new Array() console.log(a instanceof Array);//true console.log(a instanceof Object);//true // 这里a也是Object的实例的原因是,Array的原型链指向Object。 function Person(){}; let b = new Person() console.log(b instanceof Person);//true console.log(b instanceof Array);//false console.log(b instanceof Object);//true console.log(({}) instanceof Object);//true let myDate = new Date(); console.log(myDate instanceof Date);//true let simpleStr = "This is a simple string" console.log(simpleStr instanceof String);//false 基本数据类型不能判断,不是实例对象 let myString = new String() console.log(myString instanceof String);//true // 原型 function C(){} let o = new C() console.log(o instanceof C);//true C.prototype = {}//改变构造函数原型 console.log(o instanceof C);//false o.__proto__ = {}//改变对象原型 console.log(o instanceof C);//false
3)constructor
constructor是什么:当一个函数 F被定义时,JS引擎会为F添加 prototype 原型,然后再在 prototype上添加一个 constructor 属性,并让其指向 F 的引用,当执行 let z = new F() 时,F 被当成了构造函数,z 是F的实例对象,此时 F 原型上的 constructor 传递到了 z 上,因此 z.constructor === F。
写法就是a.constructor === Type,判断a是否是某类型,constructor对于对象类型的延伸都能准确判断,如Array,Data等。constructor除了不能判断null和undefined,其他都能判断,返回一个布尔值。
console.log((1).constructor === Number); // true console.log(true.constructor === Boolean); // true console.log(''.constructor === String); // true console.log(NaN.constructor === Number); // true console.log(function () { }.constructor === Function); // true console.log({}.constructor === Object); // true console.log([].constructor === Array); // true console.log(new Date().constructor === Date); // true console.log(new Error().constructor === Error); // true console.log(new RegExp().constructor === RegExp); // true console.log(Symbol().constructor === Symbol); // true console.log( new Map().constructor === Map); // true console.log( new Set().constructor === Set); // true
4)Object.prototype.toString.call( )
目前最完美的类型判断方法
传入一个任意的类型,返回一个"[ object Type ]",对于 Object 对象,直接调用 toString() 就能返回 [object Object] ,call可以省略。
Object.prototype.toString({}) ; // [object Object] Object.prototype.toString.call({}) ; // [object Object] Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(1) ; // [object Number] Object.prototype.toString.call(true) ; // [object Boolean] Object.prototype.toString.call(Symbol()); //[object Symbol] Object.prototype.toString.call(undefined) ; // [object Undefined] Object.prototype.toString.call(null) ; // [object Null] Object.prototype.toString.call(new Function()) ; // [object Function] Object.prototype.toString.call(new Date()) ; // [object Date] Object.prototype.toString.call([]) ; // [object Array] Object.prototype.toString.call(new RegExp()) ; // [object RegExp] Object.prototype.toString.call(new Error()) ; // [object Error] Object.prototype.toString.call(document) ; // [object HTMLDocument] Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用
JS类型转换
因为基本数据类型的值是不变的,类型转换的时候,是重新开辟空间创建新的类型的值,也就是对原先的值不会产生影响。
1.其他类型转字符串
1)toString( ) 不能转换null和undefined,因为这两没有toString方法
2)String( ) 没有限制
3)字符串加法(隐式转换)将要加的值先转换为字符串,再进行字符串拼接
let a = 23 a.toString() console.log(typeof a, a);//number 23 a = a.toString() console.log(typeof a, a);//string 23 let b = true b = b.toString() console.log(typeof b, b);//string true let c = null c = String(c) console.log(typeof c, c);//string null let d = 1 + '2' console.log(typeof d,d);//string 12 let e = true + '' console.log(typeof e,e);//string true
2.其他类型转number
1)Number( )
字符串转number:
如果字符串是合法数字,直接转为对应的数字
如果字符串不是合法数字,则转为NaN
如果字符串是空串或者是纯空格的字符串,转为0
布尔值转number:
true为1,false为0
null转化为0
undefined转化为NaN
2)parseInt( )与parseFloat( ) 它两是切分字符串为number,前面有介绍
3)隐式转换之加减运算
除了字符串加法外,其他运算都是先转化为number类型再进行计算。
console.log(2 + null); //2+0=2 console.log(2 + undefined); //2+NaN=NaN console.log(2 + true); //2+1=3 console.log(2 + false); //2+0=2 console.log(2 - "1"); //2-1=1 console.log(+"1"); // 1 console.log(-"1"); // -1
3.其他类型转Boolean
除了0,null,undefined,NaN,"",false为false,其余都为true,注意:空字符串是false,但空字符串有空格则返回true。
console.log(Boolean(""));//false console.log(Boolean(" "));//true