js:基础面试题

总结前端基础面试题范围
  • JS基础(原型、原型链、作用域、闭包、异步、单线程)
  • JS-WEB-API(DOM操作、Ajax、事件绑定)
  • JS-开发环境(版本管理、模板化、打包工具、页面渲染、性能优化)
列举几个面试题
  • JS中使用typeof能得到的哪些类型?(考点:JS变量类型)
  • 何时使用===何时使用==?(考点:强制类型转换)
  • window.onload和DOMContentLoader的区别?(考点:浏览器渲染过程)
  • 用JS创建10个标签,点击的时候弹出来对应的序号?(考点:作用域)
简述如何实现一个模块加载器,实现类似require.js的基本功能?(考点:JS模板化) 实现数组的随机排序(考点: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/…

下面这个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可操作的一个模型而已。

<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.减少浏览器内存占用
复制代码

转载于:https://juejin.im/post/5d030f1a5188256b150a2f4a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值