你不可不知的JS面试题

1、JS中有哪些内置类型?

7种。分别是boolean、number、string、object、undefined、null、symbol。

2、NaN是独立的一种类型吗?

不是。NaN是number类型。

3、如何判断是哪个类型?

Object.prototype.toString.call(),返回为[object Type]。

现在我们来验证一下。

1Object.prototype.toString.call(NaN); 2// "[object Number]" 3Object.prototype.toString.call('1'); 4// "[object String]" 5Object.prototype.toString.call([1,2]); 6// "[object Array]"

为什么使用Object.prototype.toString.call(),而不用typeof。是因为它有一点具有局限性。比如当我们判断数组类型时,打印出的是object,而不是我们想要的Array。

1typeof [1,2]; 2// "object" 3typeof new Number(1); 4// "object"

好,既然Object.prototype.toString.call()这么好用,我们不如封装一个方法。

1function getType(v) { 2 return Object.prototype.toString.call(v).match(/\[object (.+?)\]/)[1].toLowerCase(); 3} 4getType(1); 5// "number"

4、内置类型之间如何进行类型转换?

首先,我们先看几个例子。

第一个例子:

1const a = 1; 2const b = '1'; 3if(a==b){ 4 console.log('true') //true 5}

第二个例子:

1const x = 1+'1'; 2console.log(x); // 11 3const y = 1*'1'; 4console.log(y); // 1

第三个例子:

`const array = [];``if (array) {` `console.log('true'); // 返回true``} else {` `console.log('false');``}`

第四个例子:

1const array = []; 2if (array) { 3 console.log('true'); // 返回true 4} else { 5 console.log('false'); 6}

如果你还不是不相信第四个例子的操作,那么我们实际操作一下。果不其然,还是返回`true`。

我们先不着急,想它为什么会返回true。我们需要知道这两点。

四则运算转化:

  •  当遇到和字符串做 “加法” 时,会先将其转化为字符串,然后再进行字符串相加。

  •  当遇到“减法”、“乘法”、“除法”时,则会将其转化为数字,然后再进行运算。

对比转化(==):

  •  布尔值、字符串转化为数字 ;

  •  对象转化为字符串(绝大多数);

  •  null、undefined、symbol、NaN;

我们先看下对比转化中的第三点。

  •  null == undefined ,但是不等于其他。

  •  symbol不等于其他。

  •  NaN 不等于其他,关键是和自己都不相等。

好了,转为正题。第四个例子为什么会返回ture。因为[]先转化为字符串(对比转化中说过)。使用toString()方法转化,也就是'',然后''转化为数字0,最后false转化为0。0与0当然相等。

说了这么多,我们仔细来讲讲对象的数据类型转换。

对象的数据类型转换

  • valueOf

  • toString

  • Symbol.toPrimitive

我们先来个例子:

1let obj = { 2 valueOf(){ 3 return 1 4 }, 5 toString(){ 6 return '字符' 7 } 8 }; 9 console.log(obj+1);

你是不是会觉得会是[object Object]1。告诉你,不是哦!而是2。因为valueOf、toString是对象内置的方法。这里我们只是自定义了一下。我们先来证明一下是不是真的是内置的方法。

valueOf方法是转换原始值,也就是自身。toString方法是转换为字符。

对了,为什么是2呢?这就是对象的数据转换的灵活性,它会根据自身环境的适应性。转换自身,这里我们使用obj+1,会优先使用数字相加。那么我们换成alert(obj)。

1let obj = { 2 valueOf(){ 3 return 1 4 }, 5 toString(){ 6 return '字符' 7 } 8 }; 9 alert(obj);

这里则会打印出字符。因为alert方法会优先使用字符类型。

最后,我们来讲下最后的一个属性Symbol.toPrimitive。

1let obj = { 2 valueOf(){ 3 return 1 4 }, 5 toString(){ 6 return '字符' 7 }, 8 [Symbol.toPrimitive](){ 9 return 10 10 } 11 } 12 console.log(obj+1) // 11 13 alert(obj); //10

不论是相加操作,还是alert弹出。都是执行Symbol.toPrimitive。因为它的权重最高。

5、this是什么?

this指代表当前环境的上下文。

6、如何判断this的指向

  1.  默认情况(谁的方法就指向谁)

  2. 显示绑定

  3. 箭头函数

  4. 严格模式

第一种情况(谁的方法就指向谁) 

1、

1var a = 2; 2 var obj = { 3 a:1, 4 getVal(){ 5 console.log(this.a); 6 } 7 } 8 obj.getVal(); //1

2、

1class A { 2 a(){ 3 console.log(this); 4 } 5 }; 6 const f = new A(); 7 f.a(); // A {}

3、

1function fun() { 2 console.log(this) 3 }; 4 fun(); //window,这里相当于window.fun()。

第二种情况(显示绑定)

call、apply、bind方法都能显示改变this的指向。

1var value = 3; 2 var obj = { 3 value: 1 4 } 5 function get() { 6 console.log(this.value); 7 } 8 get(); // 3 9 get.call(obj); // 1 10 get.apply(obj); // 1 11 get.bind(obj)(); // 1

第三种情况(箭头函数)

箭头函数的this与function中的this指向不同,它指向其外部的上下文。

1var value = 3; 2 var obj = { 3 value: 1, 4 get: ()=> { 5 console.log(this.value); 6 } 7 } 8 obj.get(); // 3

第四种情况 (严格模式

严格模式下,方法直接被调用的时候,方法内部的`this`不会指向`window`。

1'use strict' 2function fun() { 3 console.log(this) 4} 5fun(); //undefined

7、什么是prototype?

prototype就是原型对象,它是函数所独有的,它包含了一个函数(类)所有的实例共享的属性和方法。

1function A() {}; 2A.prototype.get=()=>{ 3 console.log('我是get方法'); 4} 5var a1 = new A(); 6a1.get(); // 我是get方法 7var a2= new A(); 8a2.get(); // 我是get方法

a1和a2都是A的实例,所以他们都有A的原型对象上的get方法属性。

8、将方法设置在prototype上和设置在构造函数的this上有什么区别?

1function A() {}; 2 A.prototype.get = () => { 3 console.log('我是A'); 4 } 5 6 7 function B() { 8 this.get = () => { 9 console.log('我是B'); 10 } 11 };
  • 绑定在`prototype`上的方法只会在内存中存储一份,每个实例都会根据原型链找到构造函数上的这个方法,然后调用。

  • 绑定在构造函数`this`上的方法会在每次实例化的时候都在内存中创建一次,也是`new`几次,就会创建几次。

9、什么是__proto__?

  •  __proto__是浏览器内部的属性,并非js标准属性。(一般我们不会直接操作它)

  •  每个对象都有__proto__,且指向构造函数的prototype。(非常重要,但是null和undefined没有__proto__)

第二点注意,下面两个例子都返回true。

1function F() {}; 2 const f = new F(); 3 f.__proto__ === F.prototype?console.log('true'):console.log('false'); //true
1const n = new Number(1); 2n.__proto__ === Number.prototype?console.log('true'):console.log('false'); // true

10、对象的原型链组成?

原型链:

1function A() {}; 2 const a = new A(); 3 a.__proto__===A.prototype?console.log('true'):console.log('false');//true 4 console.log(A.prototype); // {constructor:f} 5 A.prototype.get=()=>{ 6 console.log('这是get') 7 } 8 console.log(A.prototype); // {get:f,constructor:f} //打印出为一个对象 9 // 以下两行代码为举例 10 const obj = new Object({get:()=>{},constructor:()=>{}}) 11 console.log(obj); 12 13 A.prototype.__proto__===Object.prototype?console.log('true'):console.log('false');//true

11、构造函数的原型链?

众所周知,构造函数也是对象。我们知道创建构造函数有两种方法。

1、

1function A() {}; 2 console.log(A); //ƒ A() {}

2、

1const B = new Function(); 2 console.log(B); //ƒ anonymous() {}

所以说,我们看下A.__proto===Function.prototype是否成立。

1function A() {}; 2 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的指向也是可以被改变的,不过真的没啥用)

1function A() {}; 2 A.prototype.constructor===A?console.log('true'):console.log('false');//true
1function A() {}; 2const a = new A(); 3console.log(a instanceof A) // true

13、call、apply、bind的作用是什么?

它们都是为了改变方法内部this的指向。

14、call、apply怎么区别?

  •  call和apply第一个参数均为this的指向。

  •  call的其余参数就是一个普通的参数列表。

  •   apply除了第一个参数外,只接受一个数组类型的参数。

call的用法:

1const obj = {name:'maomin'}; 2 function get(age,sex) { 3 console.log(` 4 我的名字:${this.name} 5 我的年龄:${age} 6 我的性别:${sex} 7 `) 8 } 9 get.call(obj,18,'男'); 10 //我的名字:maomin 11 //我的年龄:18 12 //我的性别:男

apply的用法:

1const obj = {name:'maomin'}; 2 function get(age,sex) { 3 console.log(` 4 我的名字:${this.name} 5 我的年龄:${age} 6 我的性别:${sex} 7 `) 8 } 9 get.apply(obj,[18,'男']); 10 //我的名字:maomin 11 //我的年龄:18 12 //我的性别:男

15、bind与call和apply的不同?

  •  第一个参数为this的指向,其余参数是一个普通的参数列表。(这一点跟call很像)

  •  返回的是一个函数,需要再调用一下。(bind可以实现柯里化)

1、

1function get(x,y,z) { 2 console.log(x,y,z) 3 } 4 console.log(get.bind(null,'红','黄','蓝')) 5 // ƒ (x,y,z) { 6 // console.log(x,y,z) 7 // } 8 get.bind(null,'红','黄','蓝')(); // 红 黄 蓝

2、

1function get(x,y,z) { 2 console.log(this.name,x,y,z) 3 } 4 get.bind({name:'maomin'},'红','黄','蓝')(); // maomin 红 黄 蓝

柯里化:

1function get(x,y,z) { 2 console.log(this.name,x,y,z) 3 } 4 get.bind({name:'maomin'}).bind(null,'红').bind(null,'黄').bind(null,'蓝')(); // maomin 红 黄 蓝

谢谢浏览,下期再见

下一期更新: 继承

本文转转自微信公众号前端历劫之路原创https://mp.weixin.qq.com/s/UEFpWSAqR2pqQDB9tMJciA,如有侵权,请联系删除。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

你不可不知的JS面试题(第一期)

1、JS中有哪些内置类型?7种。分别是boolean、number、string、object、undefined、null、symbol。2、NaN是独立的一种类型吗?不是。NaN是number类型。3、如何判断是哪个类型?Object.prototype.toString.call(),返回为objectType。现在我们来验证一下。Objec