慕课网《前端JavaScript基础面试技巧》学习笔记

2018-12-09  本文已影响0人  冰淇wbq

变量类型

  1. JS中使用typeof能得到哪些类型:7种类型
typeof a//undefined
typeof undefined//undefined
typeof 'abc' //string
typeof 123 //number
typeof NaN //number
typeof true //boolean
typeof {} //object
typeof [] //object
typeof null //object
typeof console.log //function
typeof Symbol('foo') //symbol

变量计算-强制类型转换

let a=100;
let b=10;
console.log(a+b);//110

let a=100;
let b='10';
console.log(a+b);//10010
console.log(a-b);//90
100=='100'//true
0==''//true(0和''都可以转换成false)
null==undefined//true(null和undefined都可以转换成false)
let a=true
if(a){
    console.log(a);//true
}
let b=100;
if(b){
    console.log(b);//100
}
let c='';
if(c){
console.log('c')
}
//c=''是false,if语句不执行
console.log(10&&0);//0
console.log(''||'abc');//abc
console.log(!window.abc);//true
//判断一个变量会被当做true还是false
var a=100;
console.log(!!a);//true
  1. 何时使用===,何时使用 ==
//仅有这种情况使用'=='
if(obj.a==null){
  //此时条件相当于obj.a===null||obj.a===undefined,简写形式
  //这是jQuery源码中推荐的写法
}

除此之外,其它情况均建议使用'==='

  1. JS有哪些内置函数
let a=4.3;
console.log(Math.round(a));
console.log(Math.ceil(a));
console.log(Math.floor(a));
console.log(Math.max(5,3));
console.log(Math.min(1,4));
function random(min,max) {
    return min+Math.random()*(max-min)
}
console.log(random(1,10));
  1. JS变量按照存储方式分为哪些类型,并描述其特点
  1. 如何理解JSON
JSON.stringify({a:10,b:20}) //"{"a":10,"b":20}"将对象转换为字符串
JSON.parse('{"a":10,"b":20}') //{a: 10, b: 20}把字符串转换为对象

原型和原型链

function Foo(name,age) {
    this.name=name;
    this.age=age;
    this.class='class-1';
//    return this;//默认有这一行
}
var f=new Foo('wbq',22);
var a={};//其实是var a=new Object()的语法糖
var b=[];//其实是var b=new Array()的语法糖
function Foo() {};//其实是var Foo=new Function(){}的语法糖
var obj={};obj.a=100;
var arr=[];arr.a=100;
function fn(){};fn.a=100
console.log(obj.__proto__);//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(arr.__proto__);//[constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
console.log(fn.__proto__);//ƒ () { [native code] }
console.log(fn.prototype);//{constructor: ƒ}
console.log(obj.__proto__===Object.prototype);//true

function Foo(name,age) {
    this.name=name;
    this.age=age;
}
Foo.prototype.alertName=function () {
    alert(this.name)
}
var f=new Foo('wbq');
f.printName=function () {
    console.log(this.name)
}
f.printName();
f.alertName();
  1. for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
function Foo(name,age) {
    this.name=name;
    this.age=age;
}
Foo.prototype.alertName=function () {
    alert(this.name)
}
var f=new Foo('wbq');
f.printName=function () {
    console.log(this.name)
}
f.printName();
f.alertName();
for(let i in f){
    console.log(i);//name,age,printName,alertName
}
//如何只遍历对象自身的属性,不遍历继承的可枚举属性
for(let i in f){
    if(f.hasOwnProperty(i)){
        console.log(i,f[i])
    }
}
  1. Object.keys(obj)
console.log(Object.keys(f));// ["name", "age", "printName"]

let obj={
    'name':'wbq',
    'age':20,
    sayName(){
        console.log(this.name)
    }
}
console.log(Object.keys(obj));//[ 'name', 'age', 'sayName' ]
console.log(Object.values(obj));//[ 'wbq', 20, [Function: sayName] ]


console.log(Object.entries(obj));
// [ [ 'name', 'wbq' ],
//     [ 'age', 20 ],
//     [ 'sayName', [Function: sayName] ] ]
  1. Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

  1. Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。

  1. Reflect.ownKeys(obj)

Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

如果对象本身没有某个属性,则通过proto向上查找,最终都没有这个属性,则返回null,这种通过proto一级一级向上查找,则形成了原型链

  1. 如何准确判断一个变量是数组类型
var arr=[]
arr instanceof Array    //true
typeof arr    //object    typeof无法准确判断是否是数组
  1. 写一个原型链继承的例子
    function Animal(name){
        this.name=name
    }
    Animal.prototype.run=function(){
        console.log('run');
    };
    function Dog(name) {
        Animal.call(this,name)
    }
    Dog.prototype=new Animal();
    let dog=new Dog('wbq');
    dog.run();
    console.log(dog.name)
<div id="div1">ddd</div>

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)
    return this
}
var div1=new Elem('div1');
div1.on('click',function () {
    alert('click')
}).html('<p>链式操作</p>')
  1. 描述new一个对象的过程
//创建一个构造函数
function Foo(name,age){
 // this={}
    this.name=name
    this.age=age
 // return this
}
var f=new Foo('wbq',10);
let newFun=function (func) {
    //1.新建一个空对象,并将 构造函数的原型对象赋给这个空对象
    let obj=Object.create(func.prototype);
    //2.执行构造函数,相应参数被传入,并将this的上下文指向新创建的对象obj
    var ret=func.call(obj);
    //3.如果构造函数返回了对象,就舍弃之前创建的对象obj,newObj = ret
    if(typeof ret === 'object') return ret;
    else return obj;
}
var foo = function(name){
    this.name = name || 'lalaBao';
}
var newObj = newFun(foo);
console.log(newObj);

作用域和闭包

  1. 说一下对变量提升的理解
console.log(a);
let a=10;//Uncaught ReferenceError: a is not defined
var a;//undefined

fn('wbq');
function fn(name) {
    console.log(name);//wbq
}
  1. 说明this几种不同的使用场景
functon Foo(name){
    this.name=name;
}
var f=new Foo('wbq')
var obj={
    name:'wbq',
    printName:function(){
        console.log(this.name)
    }
}
obj.printName();
function fn(){
    console.log(this);
}
fn();
function fn1(name,age){
    console.log(name);
    console.log(this);
}
fn1('wbq');
fn1.call({x:100},'zhangsan',20);
fn1.apply({x:100},['zhangsan',20]);
 //bind在函数声明的形式后不可用,必须是函数表达式
var fn2=function (name,age){
    console.log(name);
    console.log(this);
}.bind({y:200});
fn2('zhangsan',20)
  1. 创建10个<a>标签,点击时弹出对应序号

错误写法

//使用let形成一个块级作用域
for(let i=0;i<10;i++){
    var a=document.createElement('a');
    a.innerHTML=i;
    a.onclick=function () {
        alert(i)
    };
    document.body.appendChild(a);
}
//使用闭包
定义自执行函数,就是不同调用,只要定义完成,立即执行的函数
for(var i=0;i<10;i++){
    var a=document.createElement('a');
    a.innerHTML=i;
    (function (i) {
        a.onclick=function () {
            alert(i)
        };
    })(i);

    document.body.appendChild(a);
}
  1. 如何理解作用域
    JavaScript的作用域和作用域链
①没有块级作用域
    if(true){
        var name='zhangsan'
    }
    console.log(name)//'zhangsan'
②只有全局和函数作用域
    var a=100;
    function fn(){
        var a=200;
        console.log('fn',a)
    }
    console.log('global',a)
    fn()
 
  1. 实际开发中闭包的应用
/闭包实际应用中主要用于封装变量,收敛权限
      function isFirstLoad(){
             var _list=[];
              return function(id){
                 if(_list.indexOf(id)>=0){
                     return false;
                 }else{
                    _list.push(id);
                    return true;
                 }
              }
      }
      //使用
      var firstLoad=isFirstLoad();
      firstLoad(10);//true
      firstLoad(10);//false
    //你在 isFirstLoad 函数外面,根本不可能修改掉_list的值

异步和单线程

  1. 同步和异步的区别是什么?分别举一个同步和异步的例子
//同步
console.log(100);
alert(200)
console.log(300);
//异步
console.log(100);
setTimeout(function(){
    console.log(200);
},1000)
console.log(300);
  1. 前端使用异步的场景有哪些

它们共同的特点是需要等待,由于js是一个单线程语言,为了避免阻塞,所以要使用异步

//fetch
    console.log('start');
    fetch("./test-test.json").then(res=>res.json())
        .then(data=>{
            console.log(data)
        })
        .catch(error=>{
        console.log('error')
    })
    console.log('end');
//img loaded    
    console.log('start');
    var img=document.createElement('img');
    img.onload=function () {
        console.log('loaded')
    };
    img.src='https://box.bdimg.com/static/fisp_static/common/img/searchbox/logo_news_276_88_1f9876a.png'
    console.log('end');
    document.body.appendChild(img);
//事件    
    <button id="btn">点击</button>
    console.log('start');
    var btn=document.getElementById('btn');
    btn.addEventListener('click',function () {
        console.log('clicked')
    })
    console.log('end');

其它知识点

  1. 获取2017-07-13格式的日期
    function formatDate(dt) {
        if (!dt) {
            dt = new Date();
        }
        var year = dt.getFullYear()
        var month = dt.getMonth() + 1
        var date = dt.getDate()
        if (month < 10) {
            month = '0' + month
        }
        if (date < 10) {
            date = '0' + date
        }
        return year + '-' + month + '-' + date
    }
    var dt
    dt = new Date()
    alert(formatDate(dt))
    
    function getYearMonthDate(dt=new Date()) {
    let year=dt.getFullYear();
    let month=dt.getMonth()+1;
    let date=dt.getDate();
    if(month<10){
        month='0'+month
    }
    if(date<10){
        date='0'+date
    }
    return `${year}-${month}-${date}`
}
console.log(getYearMonthDate());

  1. 获取随机数,要求是长度一致的字符串格式
    var random = Math.random()
    random = random + '0000000000' //10个0
    random=random.slice(0,10) //slice() 方法返回一个从0开始到1结束(不包括结束)选择的数组的一部分,浅拷贝到一个新数组对象。原始数组不会被修改
    console.log(random);
  1. 写一个能遍历对象和数组的通用forEach函数
    function myForEach(obj, fn) {
        var key
        if (obj instanceof Array) { //判断是否为数组
            obj.forEach(function (item, index) {
                fn(index, item)
            })
        } else { //不是数组就是对象
            for (key in obj) {
                fn(key, obj[key])
            }
        }
    }
    var arr = [1, 2, 3] //参数顺序换了,为了和对象的遍历格式一致
    myForEach(arr, function (index, item) {
        console.log(index, item);
    })
    var obj = {x: 100, y: 200}
    myForEach(obj, function (key, value) {
        console.log(key, value);
    }) 

DOM和BOM

  1. DOM是哪种基本的数据结构:树
  2. DOM操作常用的API有哪些
  1. DOM节点的attr和property有何区别
  1. 如何检测浏览器的类型:navigator.userAgent
var ua=navigator.userAgent
var isChrome=ua.indexOf('Chrome')
console.log(isChrome);
  1. 拆解url的各部分
//location
console.log(location.href);
console.log(location.protocol); //协议 http https 
console.log(location.pathname); //域名之后的路径 
console.log(location.search);
console.log(location.hash);

事件

  1. 编写一个通用的事件监听函数
function bindEvent(elem,type,fn) {
    elem.addEventListener(type,fn)
}
var a=document.getElementById('link1');
bindEvent(a,'click',function (e) {
    e.preventDefault();//阻止默认行为
    console.log('clicked')
});
  1. 描述事件冒泡流程
  1. 对于一个无限下拉加载图片的页面,如何给每个图片绑定事件

利用事件委托,事件都有事件冒泡机制,给父级元素绑定事件,通过e.target找到事件源

var oUl=document.getElementsByTagName('ul')[0];
oUl.addEventListener('click',function (e) {
    let target=e.target;
    if(target.nodeName=='LI'){
        console.log(target.innerHTML)
    }
});

存储与Ajax

  1. 请描述一下cookie,sessionStorage,和localStorage的区别
  1. 手动编写一个ajax,不依赖第三方库
var xhr=new XMLHttpRequest()
xhr.open('GET','/api',false)
xhr.onreadystatechange=function(){ //这里的函数异步执行 if(xhr.readyState==4){
    if(xhr.status==200){
        alert(xhr.responseText)
        }
    } 
}

xhr.send(null)
  1. 跨域的几种实现方式

    浏览器有同源策略,不允许ajax访问其他域接口

    跨域条件:协议、域名、端口,有一个不同就算跨域

devServer: {
    historyApiFallback: true,
    noInfo: true,
    overlay: true,
    proxy:{
        "/api/":{
            target:"http://testmove.kandayi.com.cn/",
            changeOrigin:true
        }
    }
  },

模块化

模块化本身就是一个面试的问题

//util.js
function getFormatDate(dt=new Date(),type=1) {
    let year=dt.getFullYear();
    let month=dt.getMonth()+1;
    let date=dt.getDate();
    if(type==1){
        if(month<10){
            month='0'+month
        }
        if(date<10){
            date='0'+date
        }
        return `
        ${year}-${month}-${date}
    `
    }else{
        return `
        ${year}年${month}月${date}日
    `
    }
}
//a-util.js
function aGetFormatDate(date) {
    return getFormatDate(date,2)
}
//a.js
var dt=new Date();
console.log(aGetFormatDate(dt));
//index.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="util.js"></script>
<script src="a-util.js"></script>
<script src="a.js"></script>
<script>

</script>
</body>
</html>
//util.js
define(function () {
    return {
        getFormatDate:function (date,type) {
            let year=date.getFullYear();
            let month=date.getMonth()+1;
            let day=date.getDate();
            if(type==1){
                if(month<10){
                    month='0'+month
                }
                if(day<10){
                    day='0'+day
                }
                return `
        ${year}-${month}-${day}
    `
            }else{
                return `
        ${year}年${month}月${day}日
    `
            }
        }
    }
})
//a-util.js
define(['./util.js'],function (util) {
    return {
        aGetFormatDate:function (date) {
            return util.getFormatDate(date,2)
        }
    }
})
//a.js
define(['./a-util.js'],function (aUtil) {
    return {
        printDate:function (date) {
            console.log(aUtil.aGetFormatDate(date))
        }
    }
})
//main.js
require(['./a.js'],function (a) {
    var date=new Date();
    a.printDate(date);
});
//test.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.bootcss.com/require.js/2.3.6/require.min.js" data-main="./main.js"></script>
<script>

</script>
</body>
</html>

//a-util.js
var getFormatDate=require('util');
module.exports={
    aGetFormatDate:function(date) {
        return getFormatDate(date,2)
    }
}

//util.js
module.exports={
    getFormatDate:function (dt=new Date(),type=1){
        let year=dt.getFullYear();
        let month=dt.getMonth()+1;
        let date=dt.getDate();
        if(type==1){
            if(month<10){
                month='0'+month
            }
            if(date<10){
                date='0'+date
            }
            return `
        ${year}-${month}-${date}
    `
        }else{
            return `
        ${year}年${month}月${date}日
    `
        }
    }
}

构建工具

常用Git命令

https://git.coding.net/limiywbq/test.git
mkdir js-git-test
cd js-git-test
git init
echo "# js-git-test" >>README.md
git add README.md
cat README.md
git status
git commit -m 'first commit'
git push origin master

上线流程要点

回滚流程要点

linux基本命令

mkdir a:创建文件夹
ls:查看文件夹的名字
ll:查看文件夹下的内容
cd a:进入a文件夹
pwd:查看文件夹所有文件路径
cd ..:返回上一级文件夹
rm -rf a:删除文件夹a
vi a.js:创建编辑a.js
i:在文件里输入内容
ESC:wq:退出并保存文件
cat a.js:查看文件全部内容
rm a.js:删除文件

页面加载与性能优化

  1. 从输入url到得到HTML的详细过程
    • 浏览器根据DNS服务器得到域名的IP地址
    • 向这个IP的机器发送http请求
    • 服务器收到、处理并返回http请求
    • 浏览器得到返回内容
  2. window.onload和DOMContentLoaded的区别
window.addEventListener('load',function(){
//页面的全部资源加载完成才会执行,包括图片视频等
})
document.addEventListener('DOMContentLoaded',function(){
//DOM渲染完即可执行,此时图片视频等可能还没加载完
})

  1. 性能优化

原则:

从哪里入手
性能优化的几个示例
<img id="img1" src="preview.png" data-realsrc="abc.png"/>
<script>
var img1=document.getElementById('img1');
img1.src=img1.getAttribute('data-realsrc');
</script>
//未缓存DOM查询
var i
for(i=0;i<document.getElementsByTagName('p').length;i++){
    //todo
}
//缓存了DOM查询
var pList=document.getElementsByTagName('p')
var i
for(i=0;i<pList.length;i++){
    //todo
}

这样可以避免多次执行DOM查询

var listNode=document.getElementById('list')
//插入10个li标签 
var frag=document.createDocumentFragment(); 
var x,li 
for(x=0;x<10;x++){         li=document.createElement('li')
li.innerHTML='List item'+x frag.appendChild(li) } 
listNode.appendChild(frag)

安全性与面试技巧

上一篇下一篇

猜你喜欢

热点阅读