1、JS中有哪些内置类型?
7种。分别是boolean
、number
、string
、object
、undefined
、null
、symbol
。
2、NaN是独立的一种类型吗?
不是。NaN是number
类型。
3、如何判断是哪个类型?
Object.prototype.toString.call()
,返回为[object Type]
。
现在我们来验证一下。
Object.prototype.toString.call(NaN);
// "[object Number]"
Object.prototype.toString.call('1');
// "[object String]"
Object.prototype.toString.call([1,2]);
// "[object Array]"
为什么使用Object.prototype.toString.call()
,而不用typeof
。是因为它有一点具有局限性。比如当我们判断数组类型时,打印出的是object
,而不是我们想要的Array
。
typeof [1,2];
// "object"
typeof new Number(1);
// "object"
好,既然Object.prototype.toString.call()
这么好用,我们不如封装一个方法。
function getType(v) {
return Object.prototype.toString.call(v).match(/\[object (.+?)\]/)[1].toLowerCase();
}
getType(1);
// "number"
4、内置类型之间如何进行类型转换?
首先,我们先看几个例子。
第一个例子:
const a = 1;
const b = '1';
if(a==b){
console.log('true') //true
}
第二个例子:
const x = 1+'1';
console.log(x); // 11
const y = 1*'1';
console.log(y); // 1
第三个例子:
const array = [];
if (array) {
console.log('true'); // 返回true
} else {
console.log('false');
}
第四个例子:
if([] == false) {
console.log('true'); //返回true
} else {
console.log('false');
}
如果你还不是不相信第四个例子的操作,那么我们实际操作一下。果不其然,还是返回true
。我们先不着急,想它为什么会返回true
。我们需要知道这两点。
四则运算转化:
1. 当遇到和字符串做 “加法” 时,会先将其转化为字符串,然后再进行字符串相加。
2. 当遇到“减法”、“乘法”、“除法”时,则会将其转化为数字,然后再进行运算。
对比转化(==):
- 布尔值、字符串转化为数字 ;
- 对象转化为字符串(绝大多数);
- null、undefined、symbol、NaN;
我们先看下对比转化中的第三点。
null == undefined
,但是不等于其他。)symbol
不等于其他。NaN
不等于其他,关键是和自己都不相等。)好了,转为正题。第四个例子为什么会返回ture
。因为[]
先转化为字符串(对比转化中说过)。使用toString()
方法转化,也就是''
,然后''
转化为数字0
,最后false
转化为0
。0
与0
当然相等。
说了这么多,我们仔细来讲讲对象的数据类型转换。
对象的数据类型转换
valueOf
toString
Symbol.toPrimitive
我们先来个例子:
let obj = {
valueOf(){
return 1
},
toString(){
return '字符'
}
};
console.log(obj+1);
你是不是会觉得会是[object Object]1
。告诉你,不是哦!而是2
。因为valueOf
、toString
是对象内置的方法。这里我们只是自定义了一下。我们先来证明一下是不是真的是内置的方法。)valueOf
方法是转换原始值,也就是自身。toString
方法是转换为字符。对了,为什么是2
呢?这就是对象的数据转换的灵活性,它会根据自身环境的适应性。转换自身,这里我们使用obj+1
,会优先使用数字相加。那么我们换成alert(obj)
let obj = {
valueOf(){
return 1
},
toString(){
return '字符'
}
};
alert(obj);
这里则会打印出字符
。因为alert
方法会优先使用字符类型。
最后,我们来讲下最后的一个属性Symbol.toPrimitive
。
let obj = {
valueOf(){
return 1
},
toString(){
return '字符'
},
[Symbol.toPrimitive](){
return 10
}
}
console.log(obj+1) // 11
alert(obj); //10
不论是相加操作,还是alert
弹出。都是执行Symbol.toPrimitive
。因为它的权重最高。
5、this是什么?
this
指代表当前环境的上下文。
6、如何判断this的指向
默认情况(谁的方法就指向谁)
显示绑定
箭头函数
严格模式
第一种情况(谁的方法就指向谁)
1、
var a = 2;
var obj = {
a:1,
getVal(){
console.log(this.a);
}
}
obj.getVal(); //1
2、
class A {
a(){
console.log(this);
}
};
const f = new A();
f.a(); // A {}
3、
function fun() {
console.log(this)
};
fun(); //window,这里相当于window.fun()。
第二种情况(显示绑定)
call
、apply
、bind
方法都能显示改变this
的指向。
var value = 3;
var obj = {
value: 1
}
function get() {
console.log(this.value);
}
get(); // 3
get.call(obj); // 1
get.apply(obj); // 1
get.bind(obj)(); // 1
第三种情况(箭头函数)
箭头函数的this
与function
中的this
指向不同,它指向其外部的上下文。
var value = 3;
var obj = {
value: 1,
get: ()=> {
console.log(this.value);
}
}
obj.get(); // 3
第四种情况 (严格模式 )
严格模式下,方法直接被调用的时候,方法内部的this
不会指向window
。
'use strict'
function fun() {
console.log(this)
}
fun(); //undefined
7、什么是prototype?
prototype
就是原型对象,它是函数所独有的,它包含了一个函数(类)所有的实例共享的属性和方法。
function A() {};
A.prototype.get=()=>{
console.log('我是get方法');
}
var a1 = new A();
a1.get(); // 我是get方法
var a2= new A();
a2.get(); // 我是get方法
a1
和a2
都是A
的实例,所以他们都有A
的原型对象上的get
方法属性。
8、将方法设置在prototype上和设置在构造函数的this上有什么区别?
function A() {};
A.prototype.get = () => {
console.log('我是A');
}
function B() {
this.get = () => {
console.log('我是B');
}
};
绑定在
prototype
上的方法只会在内存中存储一份,每个实例都会根据原型链找到构造函数上的这个方法,然后调用。绑定在构造函数
this
上的方法会在每次实例化的时候都在内存中创建一次,也是new
几次,就会创建几次。
9、什么是__proto__?
_proto_
是浏览器内部的属性,并非js
标准属性。(一般我们不会直接操作它)每个对象都有
_proto_
,且指向构造函数的prototype
。(非常重要,但是null
和undefined
没有_proto_
)
第二点注意,下面两个例子都返回true
。
function F() {};
const f = new F();
f.__proto__ === F.prototype?console.log('true'):console.log('false'); //true`
`const n = new Number(1);
n.__proto__ === Number.prototype?console.log('true'):console.log('false'); // true
10、对象的原型链组成?
原型链:
function A() {};
const a = new A();
a.__proto__===A.prototype?console.log('true'):console.log('false');//true
console.log(A.prototype); // {constructor:f}
A.prototype.get=()=>{
console.log('这是get')
}
console.log(A.prototype); // {get:f,constructor:f} //打印出为一个对象
// 以下两行代码为举例
const obj = new Object({get:()=>{},constructor:()=>{}})
console.log(obj);
A.prototype.__proto__===Object.prototype?console.log('true'):console.log('false');//true
11、构造函数的原型链?
众所周知,构造函数也是对象。我们知道创建构造函数有两种方法。1、
function A() {};
console.log(A); //ƒ A() {}
2、
const B = new Function();
console.log(B); //ƒ anonymous() {}
所以说,我们看下A.__proto===Function.prototype
是否成立。
function A() {};
A.__proto__===Function.prototype?console.log('true'):console.log('false');//true
同理,构造函数的原型链:验证一下,
Function.prototype.__proto__===Object.prototype?console.log('true'):console.log('false');//true
那么,我们又有另一个疑问?Function.__proto__
指向谁呢?
Function.__proto__===Function.prototype?console.log('true'):console.log('false');//true
Function.prototype
比较特殊,它是浏览器自身创建出来的内置对象。同样,Object.prototype
也是浏览器引擎创建出来的内置对象,它们都指向null
。)
12、prototype上的constructor是什么?
每一个函数的原型对象上的constructor
都指向函数本身,目前它并没有什么作用,或许可以当作instanceof
来使用(当然constructor
的指向也是可以被改变的,不过真的没啥用)
function A() {};
A.prototype.constructor===A?console.log('true'):console.log('false');//true
function A() {};
const a = new A();
console.log(a instanceof A) // true
13、call、apply、bind的作用是什么?
它们都是为了改变方法内部this
的指向。
14、call、apply怎么区别?
call
和apply
第一个参数均为this
的指向。call
的其余参数就是一个普通的参数列表。apply
除了第一个参数外,只接受一个数组类型的参数。
call
的用法:
const obj = {name:'maomin'};
function get(age,sex) {
console.log(`
我的名字:${this.name}
我的年龄:${age}
我的性别:${sex}
`)
}
get.call(obj,18,'男');
//我的名字:maomin
//我的年龄:18
//我的性别:男
apply
的用法:
const obj = {name:'maomin'};
function get(age,sex) {
console.log(`
我的名字:${this.name}
我的年龄:${age}
我的性别:${sex}
`)
}
get.apply(obj,[18,'男']);
//我的名字:maomin
//我的年龄:18
//我的性别:男
15、bind与call和apply的不同?
第一个参数为
this
的指向,其余参数是一个普通的参数列表。(这一点跟call
很像)返回的是一个函数,需要再调用一下。(
bind
可以实现柯里化)
1、
function get(x,y,z) {
console.log(x,y,z)
}
console.log(get.bind(null,'红','黄','蓝'))
// ƒ (x,y,z) {
// console.log(x,y,z)
// }
get.bind(null,'红','黄','蓝')(); // 红 黄 蓝
2、
function get(x,y,z) {
console.log(this.name,x,y,z)
}
get.bind({name:'maomin'},'红','黄','蓝')(); // maomin 红 黄 蓝`
柯里化:
function get(x,y,z) {
console.log(this.name,x,y,z)
}
get.bind({name:'maomin'}).bind(null,'红').bind(null,'黄').bind(null,'蓝')(); // maomin 红 黄 蓝
下一期更新 请关注 第二期
作者:Vam的金豆之路
主要领域:前端开发
我的微信:maomin9761
微信公众号:前端历劫之路
本文转转自微信公众号前端历劫之路原创https://mp.weixin.qq.com/s/J3f_UHADDvlIYLNAeWwUpQ,如有侵权,请联系删除。