2019-09-09 JS面试题(持续更新中)

1、JS 中的 MUL 函数

function mul(x){
    return function(y){
         return function(z){
              return x*y*z
         }
    } 
}
var result = mul(2)(3)(4);
console.log(result,'result');//24

2、JS 中 slice 和 splice 的区别?

var arr = [0,1,2,3,4,5,6,7,8,9];
console.log(arr.slice(2,9));//[2,3,4,5,6,7,8],如果此时打印arr,显示的数据结构并未发生改变,和之前的值是一样的。
console.log(arr.splice(2,9));//[2,3,4,5,6,7,8,9]; 如果此时打印arr,的数据,显示的结果是 [0,1]。数据结构已经发生改变了。

     总结一下:

      slice(start,end) 方法,返回一个新数组,包含从 start 到end(不包含该元素) 的数组元素。(索引从0开始且 不会改变原数组,而是返回一个子数组)。

           start 参数:必须,规定从哪个位置开始选取,如果为负数,规定从数组的尾部开始选取,-1是指最后一个元素。

           end  参数:可选。如果没有这个参数的话,那么指的是从start开始到数组结束的所有元素,如果这个参数为负数,那么规定是从数组尾部开始算起的元素。

      splice():该方法向或者从数组中添加或者删除,返回被删除的数据。(该方法会改变原数组)

           splice(index,howmany,item1,...itemx):

                index 参数:必须,整数,规定添加或删除的位置,使用负数的话,则表示从数组的尾部开始。

                howmany 参数:必须,要删除的数量,如果为0,则不删除数据。

                item1...itemx 参数:可选,向数组添加的新数据。

     例如:

var  testArray = [0,1,2,3,4,5];
console.log(testArray.splice(2,2,'hello','world'));//[2,3]
console.log(testArray);//[0,1,'hello','world',4,5]

3、JS 中的展开运算符操作?

var mids = ['hello','world'];
var newMids = [1,2,3,..mids,4,5];
console.log(newMids);//[1,2,3,'hello','world',4,5]

4、JS 中的函数提升?

     JS 中创建函数有2中方法, 函数声明  和  函数表达式。

     函数声明:          

fn();//这个是函数声明

function fn(){
   console.log('这个是函数声明')
}

     函数表达式:

fns();// 报错, fns is not a function
 
var fns = function(){
    console.log('这个是函数表达式')
}

     由此说明:函数声明的优先级要高于函数表达式。

5、JS 中的 typeof  返回哪些数据类型?

      string  , boolean  , number, undefined  , null, object ,symbol (es6)。

6、强制类型转换 和 隐式类型转换?

      parseInt   parseFloat   number    和   ==    ===

7、添加,删除,替换,插入 到某个节点的方法

1)创建新节点

     createElement()//创建一个具体的元素
     createTextNode()//创建一个文本节点
     例如:
     元素获取body:
           var body = document.getElementsByTagName("body")[0];
           (或者   var body = document.body;)
           var div = document.createElement('div');
           div.className='create_div';
           body.appendChild(div);  //创建完毕。
           var texts = document.createTextNode('hello world');
           div.appendChild(texts);   //创建完毕。     

2)添加,移出,替换,插入
     appendChild()//添加
     removeChild()//移除
     replaceChild()//替换
     insertBefore()//插入

3)查找
     getElementsByTagName()//标签名称
     getElementsByName()//元素的Name 属性的值
     getElementById()//元素id ,唯一性。
     

8、看下面代码输出结果?

for(var i =0;i<5;i++){
    setTimeout(function(){
       console.log(i)
    },1000)
}
//5,5,5,5,5

解决办法:(8.1)将  var 变为 let  即可。

                    (8.2)使用闭包

for(var i=0;i<=5;i++){
    setTimeout(function(){
        console.log(i)
    }(i),1000)
}
//0,1,2,3,4,5

                    (8.3)


for (var i = 0; i < 5; i++) {
     (function () {
        var j = i;
        setTimeout(function () {
           console.log(j)
        }, 1000)
     })(i)
}
//0,1,2,3,4

 9、数组去重方法:

 双层for循环,Array.sort()加一行遍历冒泡,Array.filter() 加indexOf,ES6中的set去重,object键值对去重。    
function duplicateRemoval(arr){   //双层for循环
    for(let i=0;i<arr.length;i++){
       for(let j=i+1;j<arr.length;j++){
             if(arr[i]==arr[j]){
                   arr.splice(j,1);
                   j--;
             }
       }
    }
    return arr;
}
// es6 中的 set去重
function unique(arr){
   return Array.from(new Set(arr))    //或者  return [...new Set(arr)]
}
//Array.from()方法:就是一个类数组对象或者可遍历对象转换成一个真正的数组。(最基本要求是具有length属性的对象。)

//利用indexOf 去重   以及 includes (异曲同工之妙),如果有的话,则返回true,反之为false表示没有。
function unique(arr){
   if(!Array.isArray(arr)){  //用来判断是否是数组
      return
   }
   let array = [];
   for(let i=0;i<arr.length;i++){
      if(array.indexOf(arr[i]===-1)){  //这里表示没有==> 也可以换成 这样子表示:  if(!array.includes(arr[i])){//表示没有}
         arrar.push(arr[i])
      }
   }
   return array;
}
//Array.filter()  过滤数组,方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,且不会改变原始数组。
function unique(arr){
  return arr.filter(function(item,index,arr){
    return arr.indexOf(item,0)===index;   //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素。
  })
}

 10、数组的方法

       push() 向数组的末尾添加一个或多个元素,并返回新的长度。

       pop()  删除向数组末尾的一个元素,并把他作为返回值返回。

       unshift() 向数组的头添加一个元素或多个元素,并返回新的长度,向前边插入元素后,其他元素依次调整。

       shift()  删除数组头的一个元素,并把他作为返回值返回。

       slice(截取开始的索引,截取结束的索引)  向数组中提取指定元素。截取结束的索引可以不写,如果索引为负值的话,代表从后边开始计算。  

       splice(开始的索引,删除的数量)  删除数组中的指定元素,会影响原数组,并把删除的元素作为返回值返回。

       concat()   可以连接两个或多个数组,并返回新数组,不会影响原数组。

       join()   可以将数组转换为字符串。

       reverse()  用来反转数组,会影响原数组。

       sort()   用来对数组中的元素进行排序,影响原数组。

11、测试 numbers 数组的内容是什么?

const length = 4;
const numbers = [];
for(var i=0;i<length;i++);{ //注意看这里哦,多了一个分号
numbers.push(i+1);
}
numbers;//
for() 在空语句上进行4次迭代(不执行任何操作),而忽略实际将项目推入数组的块:{numbers.push(i+1);}
//上面代码等同于:
var i;
for(i=0;i<length;i++){
// do nothing;
}{
numbers.push(i+1);
}
numbers;//[5]

12、意外的全局变量

function foo(){
let a = b = 0;
a++;
return a;
}
foo();
typeof a;//'undefined'
typeof b;//'number'

//上面代码等效于:
function foo(){
let a;
window.b = 0;
a++;
return a;
}
foo();
typeof a;//undefined
typeof b;//number

 13、http 协议与 https协议的区别:

超文本传输协议HTTP协议被用于在web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了web浏览器和网站服务器之间的传输报文,
就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号,密码等支付信息。
为了解决HTTP协议这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和
服务器之间的通信加密。

HTTP和HTTPS的基本概念:
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准TCP,用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

HTTP和HTTPS区别:
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(secure sockets layer)协议用于对HTTP
协议传输的数据进行加密,从而就有了HTTPS。简单来说,HTTPS协议是SSL+HTTP协议构建的可进行加密传输,身份认证的网络协议,要比HTTP协议安全。
两者之间的主要区别是:
HTTPS协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
HTTP是超文本传输协议,信息是明文传输,HTTPS则是具有安全性的SSL加密传输协议。
HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443.
HTTP的连接很简单,是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输,身份认证的网络协议,比HTTP协议安全。
链接:https://www.cnblogs.com/sueyyyy/p/12012570.html

14、如何产生闭包?   当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包。【函数嵌套,内部函数引用了外部函数的数据(变量/函数)】

闭包是什么?
闭包是嵌套的内部函数。包含被引用变量(函数)的对象。【闭包存在于嵌套的内部函数中】
例子:
<---html代码 -->
<body onload="init()">
<p>one</p>
<p>two</p>
<p>three</p>
<p>four</p>
<p>five</p>
</body>
//js 代码
function init(){ //将变量i保存在每个段落对象上
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
ps[i].i = i;
ps[i].onclick = function(){
console.log(this.i)
}
}
}
function init(){ //加一层闭包,i已函数参数形式传递给内层函数
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
(function(arg){
ps[i].onclick = function(){
console.log(arg);
}
})(i)
}
}

function init(){ //加一层闭包,i以局部变量形式传递给内层函数
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
(function(){
var temp = i; //调用局部变量
ps[i].onclick = function(){
console.log(temp);
}
})()
}
}
function init(){ //加一层闭包,返回一个函数作为响应事件
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
ps[i].onclick = function(arg){
return function(){
console.log(arg)
}
}(i)
}
}
function init(){
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
ps[i].onclick = new Function("console.log("+i+")")
}
}

//错误的写法:
function init(){
var ps = document.getElementsByTagName('p');
for(var i=0;i<ps.length;i++){
ps[i].onclick = function(){
console.log(i);//这里会输出5,不管点击那个都会输出5.
}
}
}

15、js 基本数据类型和引用数据类型

基本数据类型 和 引用数据类型:
ECMAScript 包括两个不同类型的值:基本数据类型和引用数据类型。
常见的基本数据类型:
number ,string ,boolean ,undefined,null。基本数据类型是按值访问的,因为可可以直接操作保存在变量中的实际值。

引用数据类型:存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置,如对象,数组,函数等。
传值与传址:基本类型与引用类型最大的区别实际就是传值与传址的区别。
例如:var a = [1,2,3,4];
var b = a;//这个是传址,对象中传给变量的数据是引用类型,会存储在堆中。
var c = a[0];//这个是传值,把对象中的属性/数组中的数组项赋值给变量,这时变量c是基本数据类型,存储在栈内存中,改变栈中的数据不会影响堆中的数据。
浅拷贝:在定义一个对象或数组时,变量存放的往往只是一个地址。当我们使用对象拷贝时,如果属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问属性时,会根据地址回溯到父对象
指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。

深拷贝:不希望父子对象之间产生关联,那么可以使用深拷贝。

16、JS原型链

创建对象的方法:
1. var obj1 = {name:'one'}; 字面量
var obj11 = new Object({name:'one11'});

2. var M = function(name){ this.name = 'two';} 构造函数
var obj22 = new M('obj22');

3. var P = {name:'three'}; Object.create
var obj33 = Object.create(P);
原型与原型链

 


 什么原型对象?实例?构造函数?

   var M = function(name){ this.name = name;}

   var o3 = new M('o3');

   实例就是对象,在上面这例子中,o3就是实例,M就是构造函数。实例通过new一个构造函数生成的。从上图中可以知道,实例的__protpo__指向的是原型对象。实例的构造函数的prototype也是指向的原型对象。原型对象的constructor指向的是构造函数。

 

原型链:就是原型组成的链,对象的__proto__它的是原型,而原型也是一个对象,也有__proto__属性,原型的__proto__又是原型的原型,这样可以一直通过__proto__向上找,这就是原型链,找到最大的object,就终止。

 

原型对象和实例之间有什么作用?

    var M = function(name){ this.name = name;}

    var o3 = new M('0s');

    var o5 = new M();

    o3.__proto__.say = function(){

       console.log('hello world')

    }

    o3.say();//hello world

    o5.say();//hello world

    只有函数有prototype,对象是没有的。但是函数也是有__proto__的,因为函数也是对象。函数的__proto__指向的是Function.prototype。

 


 instanceof 是判断实例对象的__proto__和生成该实例的构造函数的prototype是不是引用的同一个地址。是返回true,否则返回false。实例额原型构造函数,obj.__proto__.constructor

 new 运算符原理: 一个新对象被创建,他继承自foo.prototype.构造函数返回一个对象。在执行的时候,相应的传参会被传入,同时上下文this会被指定为这个新的实例。

     new foo 等同于new foo(),只能用在不传递任何参数的情况。

 

17、js冒泡排序

function sort (temp){
for(var i=0;i<temp.length;i++){
for(var j=0;j<temp.length-i-1;j++){
if(temp[j]>temp[i]){
var result = temp[j];
temp[j] = temp[j+1];
temp[j+1] = result;
}
}
console.log(temp)
}
}
var tempArray = [1,6,2,65,9,4,3,8,6];
sort(tempArray); // 比较相邻的元素,如果后一个比前一个大,则交换位置。
//快速排序:
function quickSort(temp){
if(temp.length<=1){
return temp;
}
var index = Math.floor(temp.length/2);
var pivot = temp.splice(index,1)[0];//获取删除的数字
var arrleft = [];
var arrright = [];
for(var i=0;i<temp.length;i++){
if(temp[i]<privot){
arrleft.push(temp[i]);
}else{
arrright.push(temp[i]);
}
}
return quickSort(arrleft).concat([pivot],quickSort(arrright));
}

18、es6函数新增

函数形参的默认值:
function foo(x,y='tom'){
console.log(x,y)
}
foo('hello');//hello tom
foo('hello','');//hello
默认值与结垢赋值结合:
function foo({x,y=3}){
console.log(x,y);
}
foo({});//undefined 3;
foo({x:1,y=2});//1,2
foo();//报错
参数默认值的位置:
函数的length属性和作用域:
length:指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。
作用域:一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域。
rest参数: rest参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
function foo(...values){
var sum = 0;
for(var val of values){
sum+=val;
}
}
foo(1,2,3);//6
箭头函数: =>定义函数 (函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。不可以当作构造函数,也就是说不可以使用new命令。不可以使用arguments对象。不可以使用yield命令。)
var f = () =>5;
var sum = (nums,num2)=>num1+num2;

19、同步异步

同步异步定义:
同步和异步关注的是消息通信机制。同步,就是调用某个东西时,调用方得等待这个调用返回结果才能继续往后执行。异步,和同步相反,调用方不会立即得到结果,而是在调用发出后调用者可以继续执行后续操作,被
调用者通过状态来通知调用者,或者通过回调函数来处理这个调用。
同步操作好比排队。

20、发送http请求发生了什么?

当我们在浏览器的地址输入 www.baidu.com 然后回车,回车这一瞬间发生了什么呢?

 


 域名解析---发起TCP 3次握手--建立TCP连接后发起http请求--服务器端响应http请求,浏览器得到html代码--浏览器解析html代码,并请求html代码中的资源--浏览器对页面进行渲染呈现给用户。

21、JS 小题

1、 console.log( [] == ![] );
//打印为 true。
关系运算符,把其他数据类型转换成 number,然后比较
逻辑运算符,把数据转换成 Boolean
复杂数据类型在隐式转换时会先转成string
[].valueOf().toString() =>''
![] => false
Number('') === Number(false)

2、 console.log( 'b'+'a'++'a'+'a');
//打印为 baNaNa
字符串连接符,把其他数据类型转换成 string,然后拼接
算符运算符,把其他数据类型转换成 number,然后做加法计算
'b'+'a'+'NaN'+'a' => baNaNa

3、 console.log( NaN === NaN );
//打印为 false
NaN 不等于任何值。

4、 console.log([1,2,3] + [4,5,6]);
// 1,2,34,5,6
字符串连接符,把其他数据类型转换成string,然后拼接
[1,2,3].valueOf().toString() => 1,2,3
[4,5,6].valueOf().toString() => 4,5,6
所以结果就是: '1,2,3'+'4,5,6' => 1,2,34,5,6

5、 console.log(Math.min() > Math.max());
//true
Math.min() => Infinity
Math.max() => -Infinity

22、文本超出部分显示省略号    

/*css  单行*/
  .类名 {
     overflow:hidden;
     text-overflow:ellipsis;
     white-space:nowrap;
  }

/*多行*/
   .类名 {
     display:-webkit-box;
     -webkit-box-orient:vertical;
     -webkit-line-clamp:3;/*这里显示几行文字*/
     overflow:hidden
   }

posted on 2019-09-09 17:57  有匪  阅读(324)  评论(0编辑  收藏  举报

导航