js:基础面试题

总结前端基础面试题范围

  • JS基础(原型、原型链、做用域、闭包、异步、单线程)
  • JS-WEB-API(DOM操做、Ajax、事件绑定)
  • JS-开发环境(版本管理、模板化、打包工具、页面渲染、性能优化)
列举几个面试题

JS基础

JS中使用typeof能获得的哪些类型?
7种:number、string、undefined、boolean、symbol、object、function

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b 没有声明,可是还会显示 undefined

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'

typeof null // 'object'
复制代码
什么时候使用===什么时候使用==?
if (obj.a == null) {
    // 这里至关于obj.a === null || obj.a === undefined, 简写形式
    // jquery源码中推荐的写法
}
=== 全等:值和类型都相等
== 等:值相等 null == undefined
复制代码
JS中的内置函数
Object、Array、Boolean、Number、String、Function、Date、RegExp、Error
复制代码
JS按存储方式区分变量类型
基本类型有6种,分别是undefined,null,boolean,string,number,symbol(ES6新增)。
虽然 typeof null 返回的值是 object,可是null不是对象,而是基本数据类型的一种。
基本数据类型存储在栈内存,存储的是值。
复杂数据类型的值存储在堆内存,地址(指向堆中的值)存储在栈内存。当咱们把对象赋值给另一个变量的时候,复制的是地址,指向同一块内存空间,当其中一个对象改变时,另外一个对象也会变化。
// 值类型
var a = 10;
var b = a;
a = 11;
console.log(b); // 10

// 引用类型
var obj1 = { x: 100 }
var obj2 = obj1;
obj1.x = 200;
console.log(obj2.x) // 200

在条件判断时,除了 undefined, null, false, NaN, '', 0, -0,其余全部值都转为 true,包括全部对象。
复制代码
变量类型和计算
1.变量计算-强制类型转换
(1).字符串拼接
var a=100+10; // 110
var b=100+'10'; // '10010'
(2).==运算符
100 == '100'  // true
0 == ''  // true
null == undefined // true
(3).if语句
1.var a=true;
if(a){
   //....
}
2.var b=100;
if(b){
    //...
}
3.var c= '';
if(c){
    //..
}
(4).逻辑运算
console.log(10 && 0); // 0
console.log('' || 'abc'); // 'abc'
console.log(!window.abc); // true
复制代码
如何理解JSON
JSON只不过是一个JS对象而已

JSON.stringify({a:10, b:20});
JSON.parse('{"a":10, "b": 20}')
复制代码
原型构造函数
// 构造函数
function Foo(name, age) {
    this.name = name;
    this.age = age;
    this.class = "class-1";
    //return this 默认有这一行
}
var f = new Foo("cl", 29); // 建立多个对象

// 构造函数-扩展
1.var a={}实际上是var a=new Object()的语法糖。
2.var a=[]实际上是var a=new Array()的语法糖。
3.function Foo(){....}实际上是var Foo=new Fuction(...)
4.使用instanceof判断一个函数是不是一个变量的构造函数。

// 原型规则和示例
1.全部的引用类型(数组、对象、函数 ),都具备对象特性,便可自由扩展属性(除了"null"以外)。
var obj={};obj.a=100;
var arr=[];arr.a=100;
function fn(){}  fn.a=100;

2.全部的引用类型(数组、对象、函数 ),都有一个__proto__属性,属性值是一个普通的对象。
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

3.全部的函数,都有一个prototype属性,属性值也是一个普通的对象。
console.log(fn.prototype)

4.全部的引用类型(数组、对象、函数 ),__proto__属性值指向它的构造函数的"prototype"属性值。
console.log(obj.__proto__===Object.prototype);

5.当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。

//构造函数
function Foo(name, age){
    this.name=name;
}
Foo.prototype.alertName = function(){
    alert(this.name);
}
//建立示例
var f=new Foo('小林');
f.printName=function(){
    console.log(this.name);
}
//测试
f.printName();
f.alertName();
f.toString();//要去f.__proto__.__proto__中查找。
复制代码
原型链

instanceof
1.f instanceof Foo的判断逻辑是:
2.f的__proto__一层一层往上,可否对应到Foo.prototype。
3.再试着判断f instanceof Object。
复制代码
如何准确判断一个变量是数组类型
var arr = [];
arr instanceof Array // true
typeof arr // object、typeof是没法判断是不是数组的
复制代码
写一个原型链继承的列子
function Animal() {
    this.eat = function() {
        console.log("animal eat");
    }
}

function Dog() {
    this.back = function() {
        console.log("dog back")
    }
}

Dog.prototype = new Animal();

var hashiqi = new Dog();


function Elem(id) {
    this.elem = document.getElementById(id);
}
Elem.prototype.html = function (val){
var elem = this.elem;
if(val){
    elem.innerHTML = val;
    return this; //链式操做
}else {
    return elem.innerHTML;
}
}
Elem.prototype.on = function (type, fn){
var elem = this.elem;
elem.addEventListener(type, fn);
}
var div1 = new Elem('box');
//        console.log(div1.html());
//         div1.html('<p>2222</p>');
//         div1.on("click", function(){
//             alert("111");
//         })
div1.html('<p>2222</p>').on("click", function(){
   alert("this.text()");
})
复制代码
描述new一个对象的过程
1.新生成了一个对象
2.连接到原型
3.绑定 this
4.返回新对象

function create() {
    // 建立一个空的对象
    let obj = new Object()
    // 得到构造函数
    let Con = [].shift.call(arguments)
    // 连接到原型
    obj.__proto__ = Con.prototype
    // 绑定 this,执行构造函数
    let result = Con.apply(obj, arguments)
    // 确保 new 出来的是个对象
    return typeof result === 'object' ? result : obj
}
复制代码
this指向
(1).this要执行时才能确认值,定义时没法确认
1.做为构造函数执行
function Foo(name){
    this.name=name;
}
var f=new Foo("小林")

2.做为对象属性执行
var obj = {
      name:"A",
      printName: function(){
            console.log(this.name);
     }
}
obj.printName()

3.做为普通函数执行
function fn(){
      console.log(this)//window
}
fn()

4.call、Apple、bind
function fn1(name, age){
      alert(name);
      console.log(this)//window
}
fn1.call({x:100}, "zhangsan", 20);//{x:100}this指向
fn1.call({x:100}, ["zhangsan", 20]);//{x:100}this指向
var fn2 = function(name, age){
      alert(name);
      console.log(this);
}.bind({y:200})
fn2('zhangsan', 20)


var a={
    name: "A",
    fn: function(){
          console.log(this.name);
    }
}
a.fn() // this===a
a.fn.call({name:'B'}) // this ==={name: 'B'}
var fn1 = a.fn;
fn1 // this===window
复制代码
做用域
(1).没有块级做用域。
if(true){
    var name="zhangsan";
}
console.log(name);

(2).只有函数和全局做用域。
var a=100;
function fn(){
  var a=200;
  console.log('fn', a);
}
console.log('global', a);
fn();

(3).做用域链
var a=100;
function fn(){
    var b=200;
    console.log(a)//当前做用域没有定义的变量,即“自由变量”
    console.log(b)
}
复制代码
执行上下文
(1).范围:一段<script>或者一个函数。
(2).全局:变量定义、函数声明。一段<script>。
(3).函数:变量定义、函数声明、this、argument、函数
(4).函数声明和函数表达式的区别。
console.log(a);  //undefined
var a = 100;

fn('zhangsan')  // 'zhangsan'   20
function fn(name) {
      age=20;
      console.log(name,age);
      var age;
}
复制代码
闭包
1.函数做为返回值。
function f1(){
    var a=10;
    return function (){
         console.log(a)//自由变量,父做用域寻找
   }
}
var f =f1();
var a=2000;
f();// 10

2.函数做为函数传递。
function f1(){
    var a=10;
    return function (){
         console.log(a)//自由变量,父做用域寻找
   }
}
var f =f1();
function f2(fn){
    var a=200;
    fn();
}
f2(f1);
复制代码
说一下对变量提高的理解

详解: www.cnblogs.com/liuhe688/p/…html

下面这个ul,请写出代码,让点击每一列的时候alert其index?
<ul id="test">
    <li>这是第一条</li>
    <li>这是第二条</li>
    <li>这是第三条</li>
    <li>这是第四条</li>
    <li>这是第五条</li>
</ul>

<script>
    //第一种方式,加入index属性
    // window.onload = function() {
    //     var test = document.getElementById('test');
    //     var list = test.getElementsByTagName('li');
    //     for(var i=0; i<list.length; i++){
    //         list[i].setAttribute('index',i);
    //         list[i].addEventListener("click", function(){
    //           console.log(this.getAttribute('index'), 'index');
    //         })
    //     }
    // };
    // 第二种方式,用let申明变量
    // window.onload = function() {
    //     const test = document.getElementById('test');
    //     const list = test.getElementsByTagName('li');
    //     for(let i=0; i<list.length; i++){
    //         list[i].addEventListener("click", function(){
    //           console.log(i, 'let');
    //         })
    //     }
    // };
    //方法3,使用闭包的方式
    // window.onload = function() {
    //     var test = document.getElementById('test');
    //     var list = test.getElementsByTagName('li');
    //     for(var i=0; i<list.length; i++) {
    //         list[i].addEventListener("click", function(num) {
    //             return function() {
    //                 console.log(num);
    //             }
    //         }(i))
    //     }
    // }
    // 方法4
    // window.onload = function() {
    //     var test = document.getElementById('test');
    //     var list = test.getElementsByTagName('li');
    //     for(var i=0; i<list.length; i++){
    //         list[i].index=i
    //         list[i].addEventListener("click", function(e){
    //           console.log(e.target.index);
    //         })
    //     }
    // };
</script>
复制代码
如何理解做用域

详解: www.cnblogs.com/smyhvae/p/8…前端

异步和单线程
1.什么时候须要异步
    (1).在可能发生等待的状况。
    (2).等待过程当中不能像alert同样阻塞程序运行。
    (3).所以,因此的'等待的状况'都须要异步。
2.异步的场景
    (1).定时任务:setTimeout,setInverval。
    (2).网络请求:ajax请求,动态<img>加载。
    (3).事件绑定
3.同步和异步的区别是什么
    (1).同步会阻塞代码执行,而异步不会。
    (2).alert是同步,setTimeout是异步。

console.log(100);
setTimeout(function() {
    console.log(200);
})
console.log(300);

1.执行第一行,打印100;
2.执行setTimeout后,传入setTimeout的函数会被暂存起来,不会当即执行(单线程的特色,不能同时干两件事);
3.执行最后一行,打印300;
4.待全部程序执行完,处于空闲状态时,会立马看有木有暂存起来的要执行;
5.发现暂存起来的setTimeout中的函数无需等待时间,就当即过来执行

复制代码
获取当天格式的日期
function formatDate(dt) {
      dt = !dt ? new Date() : dt;
      let year = dt.getFullYear();
      let month = dt.getMonth() + 1;
      let data = dt.getDate();
      month = month < 10 ? ('0' + month) : month;
      data = data < 10 ? ('0' + data) : data;
      //强制转换
      return year + "-" + month + "-" + data;
}    
let dt = new Date();
console.log(formatDate(dt));
复制代码
获取随机数,要求是长度一直的字符串格式
var num = Math.random();
num = num + '0000000000';
num = num.slice(0, 10);
console.log(num);
复制代码
写一个能遍历对象和数组的forEach函数
function forEach(obj, fn) {
    if (obj instanceof Array) {
        // 准确判断是否是数组
        obj.forEach(function(item, index){
            fn(index, item);
        })
    } else {
        // 不是数组就是对象
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                fn(key, obj[key]);
            }
           
        }
    }
}

// 数组
const arr = [1,2,3];
forEach(arr, function(index, item) {
    console.log(index, item);
})

//对象
const obj = { x:100, y: 200};
forEach(obj, function(key, value){
    console.log(key, value);
})
复制代码
数组API
1.forEach
var arr=[1,2,3];
arr.forEach(function(item, index){
        //遍历数组的全部元素
         console.log(index, item);
})

2.every
var arr=[1,2,3];
var result=arr.every(function (item, index){
      //用来判断全部的数组元素,都知足一个条件
      if(item < 4){
                 return ture;
        }
})
console.log(result);

3.some
var arr=[1,2,3];
var result = arr.some(function (item, index){
     //用来判断全部的数组元素,只要有一个知足条件便可
     if(item < 2){
             return ture
      }
})
console.log(result);

4.sort
var arr=[1,4,2,3,5];
var arr2 = arr.sort(function(a, b){
        //从小到大排序
       return a-b;
       //从大到小排序
       // return b-a
})
console.log(arr2);

5.map
var arr=[1,2,3,4];
var arr2 = arr.map(function(item, index){
       //将元素从新组装,并返回
       return '<b>'+item+'</b>';
})
console.log(arr2);

6.filter
var arr=[1,2,3];
var arr2=arr.filter(function(item, index){
       //经过某一个条件过滤数组
       if(item >= 2){
              return true;
       }
})
console.log(arr2);
复制代码

JS-WEB-API

DOM节点操做

DOM能够理解为:浏览器把拿到的html代码,结构化一个浏览器能识别而且js可操做的一个模型而已。node

<div id="box">
    <p class="container"></p>
    <p></p>
    <p></p>
</div>
<script>
 var box = document.getElementById("box"); // 元素
 var boxList = document.getElementsByTagName("p"); // 集合
 console.log(boxList.length);
 console.log(boxList[0]);

 var box = document.querySelector("#box");
 console.log(box);

 var container = document.getElementsByClassName(".container");
 console.log(container);

//  property
 var box = document.querySelectorAll("p"); //集合
 console.log(box);
 var p = box[0];
 console.log(p.style.width); // 获取样式
 p.style.width = "100px"; // 修改样式
 console.log(p.className); // 获取class
 p.className = "p1"; // 修改class

 // 获取nodeName 和 nodeType
 console.log(p.nodeName);
 console.log(p.nodeType);

// Attribute
 var box = document.querySelectorAll("p"); //集合
 var p = box[0];
 p.getAttribute("data-name");
 p.setAttribute("data-name", "imooc");
 p.getAttribute("style");
 p.setAttribute("style","font-size: 30px");
 
 
// 新增节点
var box = document.getElementById("box");
// 添加新节点
var p = document.createElement("p");
p.innerHTML = "this is p";
box.appendChild(p); // 添加新建立的元素
// 移动已有节点
var p1 = document.getElementById("p1");
box.appendChild(p1);

// 获取父元素和子元素
var box = document.getElementById("box");
var parent = box.parentElement;
var child = box.childNodes;
box.removeChild(child[0]);

// 删除节点
var box =document.getElementById("box");
var child = box.childNodes;
box.removeChild(child[0]);

</script>
复制代码
DOM节点的Attribute和property有何区别
1.property只是一个JS对象的属性的修改
2.Attribute是对html标签属性的修改
复制代码
如何检测浏览器的类型
var ua = navigator.userAgent;
var isChrom = ua.indexOf("Chrome");
console.log(isChrom);

console.log(location.href); // 网址
console.log(location.protocol); //协议https
console.log(location.pathname); // 域名/p/4d6b43fda11a
console.log(location.search);
console.log(location.hash);
history.back();// 返回上页面,页面不刷新
history.forward(); //加载 history 列表中的下一个 URL。
复制代码
通用绑定事件的函数
<div id="box">
     <a >2</a>
     <a >3</a>
     <a >4</a>
 </div>
<script>
    function bindEvent(elem, type, selector, fn) {
        if (fn == null) {
            fn = selector;
            selector = null;
        }
        elem.addEventListener(type, function (e) {
            let target;
             if (selector) {
                 target = e.target;
                 if (target.matches(selector)) {
                     fn.call(target, e);
                 } else {
                     fn(e);
                 }
             }
        })
    }
let box = document.getElementById("box");
bindEvent(box, 'click', 'a', function(e){
    console.log(this.innerHTML);
})
<script>
复制代码
代理的好处
1.代码简洁
2.减小浏览器内存占用
复制代码
相关文章
相关标签/搜索