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

变量类型

  • 值类型和引用类型
  • 值类型只能存储一个值
  • 值类型复制就是值类型本身
  • 引用类型复制只是复制引用类型的指针
  • 引用类型:对象,数组,函数
  • 引用类型特点:可以无限制的扩展属性
  1. JS中使用typeof能得到哪些类型:7种类型
  • undefined string number boolean symbol object function
  • typeof不能详细区分引用类型(对象、数组)的详细类型
  • 但是可以详细区分function以及所有值类型。
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)
  • if语句
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有哪些内置函数
  • js内置函数是浏览器内核自带的,不用任何函数库引入就可以直接使用的函数。
  • Object,Array,Boolean,Number,String,Function,Date,RegExp,Error
  • Math是内置对象
  • Math内置对象常用方法
    • Math.floor():向下取整
    • Math.ceil():向上取整
    • Math.round():四舍五入
    • Math.max(a,b):取a,b之间最大值
    • Math.min(a,b):取a,b之间最小值
    • Math.random:取0-1之前的随机数
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是JS中的一个内置对象
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(){}的语法糖
  • 原型规则和示例
    • 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了'null')
    • 所有的引用类型(数组、对象、函数),都具有proto属性,属性值是一个普通的对象
    • 所有的函数,都有一个prototype属性,属性值也是一个普通对象
    • 所有的引用类型(数组、对象、函数),proto属性值指向它的构造函数的prototype属性
    • 当试图得到一个对象的某个属性时,如果对象本身没有这个属性,那么会去它的proto(即它的构造函数的prototype)中寻找
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)
  • Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

  • 大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in循环,而用Object.keys()代替。

  • Object.values(obj):方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。

  • bject.entries():方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。

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一级一级向上查找,则形成了原型链

  • instanceof
    • 用于判断引用类型属性是哪个构造函数的方法
    • f instanceof Foo的判断逻辑是:
    • f的proto一层一层往上,能否对应到Foo.prototype
  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)
  • 封装一个DOM查询
ddd
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('

链式操作

')
  1. 描述new一个对象的过程
//创建一个构造函数
function Foo(name,age){
 // this={}
    this.name=name
    this.age=age
 // return this
}
var f=new Foo('wbq',10);
  • 创建一个新对象:{}
  • 将构造函数的作用域赋给新对象(因此this指向这个新对象):this={}
  • 执行构造函数中的代码(为这个新对象添加属性):this.xxx=xxx
  • 返回新对象:return this
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);

作用域和闭包

  • 执行上下文
    • 范围:一段
      • 使用模块化解决以上问题
      • 直接,其他的根据依赖关系自动引用
      • 那两个函数,没必要做成全局变量,不会带来污染和覆盖
      //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
      
      
      
          
          
          
          Document
      
      
      
      
      
      
      
      
      • AMD
        • A:异步 M:模块 D:定义
        • require.js requirejs.org
        • 全局define函数
        • 全局require函数
        • 依赖JS会自动异步加载
        • 使用requirejs完成刚才的例子
      • CommonJS
        • CommonJS是Nodejs模块化规范,现在被大量用前端
        • 前端开发依赖的插件和库,都可以从npm获取
        • 构建工具高度自动化,使npm成本非常低
        • CommonJS本身不会异步加载JS,而是一次性同步加载出来
        • module.exports={aaa:...,bbb:...}输出模块,require(xxx.js)引用模块
      • AMD和CommonJS的使用场景
        • 需要异步加载,使用AMD
        • 使用npm后建议使用CommonJS(webpack,Node.js)
      //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}日
          `
              }
          }
      }
      
      

      构建工具

      • grunt
      • gulp
      • fis3:百度内部
      • webpack
        • new webpack.optimize.UglifyJsPlugin():js压缩

      常用Git命令

      • git add .:添加所有文件
      • git checkout xxx:还原某个文件
      • git commit -m 'xxx':提交文件到本地仓库
      • git push origin master:提交文件到远程仓库
      • git pull origin master:拉取远程仓库文件到本地
      • git branch:看当前分支
      • git checkout -b xxx:新建分支
      • git checkout xxx:切换到某个分支
      • git merge xxx:合并分支
      • git status:查看状态
      • git clone:拷贝线上项目地
      • cat README.md:查看文件
      • vi README.md:往文件里插入内容
      • git diff:查看文件修改内容
      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
      

      上线流程要点

      • 将测试完成的代码提交到git版本库的master分支
      • 将当前服务器的代码全部打包并记录版本号,备份
      • 将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:删除文件

      页面加载与性能优化

      • 加载资源的形式

        • 输入url(或跳转页面)加载HTML
        • 加载HTML中的静态资源 script link img等
      • 加载一个资源的过程

        • 浏览器根据DNS服务器得到域名的IP地址
        • 向这个IP的机器发送http请求
        • 服务器收到、处理并返回http请求
        • 浏览器得到返回内容
      • 浏览器渲染页面的过程

        • 根据HTML结构生成DOM Tree
        • 根据CSS生成CSSOM
        • 将DOM和CSSOM整合成RenderTree
        • 根据RenderTree渲染和展示
        • 遇到只有内容改变时才更改名称
        • 使用CDN
        • 使用SSR后端渲染(Vue、React):可以把后端数据直接渲染到页面中,不必要通过ajax调取后端数据,可以很大程度提高页面性能
        • 懒加载
        
        
        
        • 减少DOM查询,对DOM查询做缓存
        //未缓存DOM查询
        var i
        for(i=0;i

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

        • 合并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)
        

        安全性与面试技巧

        • XSS跨站请求攻击

          • 写一篇文章,同时偷偷插入一段

你可能感兴趣的:(慕课网《前端JavaScript基础面试技巧》学习笔记)