zoukankan      html  css  js  c++  java
  • 《前端JavaScript面试技巧》笔记一

    思考:

    • 拿到一个面试题,你第一时间看到的是什么 -> 考点
    • 又如何看待网上搜出来的永远也看不完的题海 -> 不变应万变
    • 如何对待接下来遇到的面试题 -> 题目到知识再到题目

    知识体系:

    JS基础知识

    一、变量类型和计算

    题目:

    • JS中使用typeof能得到哪些类型?
    • 何时使用 === 何时使用 == ?
    • JS中有哪些内置函数
    • JS变量按照存储方式区分为哪些类型,并描述其特点
    • 如何理解JSON

    知识点:

    /*一、变量类型*/
      /*值类型vs引用类型*/
      //从内存来说,值类型是把每个值分块存放在内存中,而引用类型是好几个变量公用一个内存块,节省内存空间。
      //引用类型包括:对象、数组、函数。引用类型的属性是可以无限扩展的,属性多了,就会占用更多的内存空间,所以引用类型是为了公用内存空间。
      //值类型
      var a = 100;
      var b = a;
      a = 200;
      console.log(b); //100
      //引用类型
      var a = {age:20};
      var b = a;
      b.age = 21;
      console.log(a.age); //21
    
      /*typeof运算符详解*/
      //typeof只能区分值类型,引用类型也只能区分function,因为function的定位非常高。
      typeof undefined //undefined (值类型)
      typeof 'abc' //string (值类型)
      typeof 123 //number (值类型)
      typeof true //boolean (值类型)
      typeof {} //object (引用类型)
      typeof [] //object (引用类型)
      typeof null //object (引用类型)
      typeof console.log //function (引用类型)
    

    /*二、变量计算---强制类型转换*/ //字符串拼接 var a = 100+10; //110 var b = 100+'10'; //'10010' //运算符 //==会把两边的值转换为true或false 100 == '100'; //true 0 == ''; //true null == undefined; //true //if语句 //if会把括号里面的值转换为true或false var a = true; if(a){...} var b = 100; if(b){...} var c = ''; if(c){...} //逻辑运算 console.log(10 && 0); //0 console.log('' || 'abc'); //'abc' console.log(!window.abc); //true //判断一个变量会被当作true还是false var a = 100; console.log(!!a);

    解题:

    JS中使用typeof能得到哪些类型?

      undefined、string、number、boolean、object、function

    何时使用 === 何时使用 == ?

    if(obj.a==null){
       //这里相当于 obj.a === null || obj.a ===undefined ,简写形式
       //这是 jquery 源码中推荐的写法
    }
    

      双等会进行强制类型转换,三等不会进行强制类型转换。

      除了上面的例子用双等,其它的都用三等。

    JS中有哪些内置函数 

      数据封装类对象
      Object
      Array
      Boolean
      Number
      String
      Function
      Date
      RegExp :正则表达式
      Error

    JS变量按照存储方式区分为哪些类型,并描述其特点

      值类型和引用类型。

      从内存来说,值类型是把每个值分块存放在内存中,而引用类型是好几个变量公用一个内存块,节省内存空间。

    如何理解JSON  

      JSON只不过是一个JS对象,也是一种数据格式。
      JSON基本的api只有两个:
      JSON.stringify({a:10,b:20}); //对象转字符串
      JSON.parse('{"a":10,"b":20}'); //字符串转对象

     

     二、原型和原型链

    题目:

    • 如何准确判断一个变量是数组类型
    • 写一个原型链继承的例子
    • 描述new一个对象的过程
    • zepto(或其他框架)源码中如何使用原型链

     知识点:

    //大写开头的函数基本都是构造函数,这么写提高代码可读性
    
    /*一、构造函数*/
      function Foo(name,age){
        this.name = name;
        this.age = age;
        this.class = 'class-1';
        //return this //默认有这一行,最好不要写
      }
      var f = new Foo('zhangsan',20);
      //var f1 = new Foo('lisi',22); //创建多个对象
      //new时把参数传进去。new函数执行时里面的this会变成空对象,给this赋值后,再把this给return回来,return回来就把值赋值给了f,这时f就具备f.name = 'zhangsan',f.age = 20,f.class ='' 'class-1'
      
    
    /*二、构造函数-扩展*/
      /*
      var a = {} 其实是 var a = new Object() 的语法糖。 构造函数是Object函数。
      var a = [] 其实是 var a = new Array() 的语法糖。 构造函数是Array函数。
      function Foo(){...} 其实是 var Foo = new Function(...)。 构造函数是Function。
      推荐前面的书写方式。
      使用instanceof判断一个函数是否是一个变量的构造函数。比如:判断一个变量是否为“数组”:变量 instanceof Array
      */
    
    /*三、原型规则和示例*/ //5条原型规则-原型规则是学习原型链的基础 //1、所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了null以外) var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn(){}; fn.a = 100; //2、所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象。 __proto__ 隐式原型 console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__); //3、所有的函数,都有一个prototype属性,属性值也是一个普通的对象。 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('zhangsan'); f.printName = function(){ console.log(this.name); } //测试 f.printName(); //zhangsan f.alertName(); //zhangsan //补充 -- 循环对象自身的属性 var item; for(item in f){ //高级浏览器已经在 for in 中屏蔽了来自原型的属性 //但是这里建议还是加上这个判断,保证程序的健壮性 if(f.hasOwnProperty(item)){ console.log(item); } } /*四、原型链*/ //构造函数 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //创建示例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //测试 f.printName(); //zhangsan f.alertName(); //zhangsan f.toString(); //要去f.__proto__.__proto__中查找 /*五、instanceof*/ //用于判断引用类型属于哪个构造函数的方法 //构造函数 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //创建示例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //测试 f.printName(); //zhangsan f.alertName(); //zhangsan f.toString(); //要去f.__proto__.__proto__中查找 //instanceof //f instanceof Foo 的判断逻辑是: //1、f 的 __proto__ 一层一层往上,能否对应到 Foo.prototype //2、再试着判断 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.bark = function(){
              console.log('dog bark');
          }
      }
      Dog.prototype = new Animal();
      //哈士奇
      var hashiqi = new Dog();
    
      /*面试时千万不要写这个例子,要写更贴近于实战的原型链例子*/
    /*用下面的例子*/

    //写一个封装DOM查询的例子
    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');
    console.log(div1.html());
    div1.html('<h2>新内容</h2>').on('click',function(){
    alert(div1.html());
    }).html('<h2>新内容新内容新内容</h2>').on('click',function(){
    alert('第二次');
    }); //链式操作


    /*div1.html('<h2>新内容</h2>')
    div1.on('click',function(){
    alert(div1.html());
    })*/

     

    描述new一个对象的过程

    /*
      1、创建一个新对象
      2、this指向这个新对象
      3、执行代码,即对this赋值
      4、返回this
     */
     /*构造函数*/
      function Foo(name,age){
        this.name = name;
        this.age = age;
        this.class = 'class-1';
        //return this //默认有这一行
      }
      var f = new Foo('zhangsan',20);
      //var f1 = new Foo('lisi',22); //创建多个对象

    zepto(或其他框架)源码中如何使用原型链

    1. 阅读源码是高效提高技能的方式。如zepto
    2. 但不能“埋头苦钻”,有技巧在其中
    3. 慕课网搜索“zepto设计和源码分析”

     

    三、作用域和闭包

    题目:

    • 说一下对变量提升的理解
    • 说明this几种不同的使用场景
    • 创建10个<a>标签,点击时弹出对应的序号
    • 如何理解作用域
    • 实际开发中闭包的应用

    知识点:

    /*一、执行上下文*/
     //范围:一段<script>或者一个函数
     //全局:变量定义、函数声明(一段<script>)
     //函数:变量定义、函数声明、this、arguments(函数)
     //PS:注意“函数声明”和“函数表达式”的区别
     //实际代码中不要下面这种写法,都是先定义,再执行,提高代码可读性。
     console.log(a); //undefined
     var a = 100;
    
     fn('zhangsan'); //'zhangsan' 20
     function fn(name){ //函数声明
      age = 20;
      console.log(name,age);
      var age;
     }
     var fn = function(){} //函数表达式
    
    
    /*二、this*/
    	//this要在执行时才能确认值,定义时无法确认。
    	//作为构造函数执行
    	//作为对象属性执行
    	//作为普通函数执行
    	//call、apply、bind
    	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
    
    
    /*作用域*/
    	/*无块级作用域*/
    	//没有块级作用域,写在里面和外面是一样的。不建议下面这种写法,程序不易读。
    	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();
    
    
    /*作用域链*/
    	//函数的父级作用域是函数定义时的作用域,不是函数执行时的作用域。
    	var a = 100;
    	function fn(){
    		var b = 200;
    
    		//当前作用域没有定义的变量,即“自由变量”
    		console.log(a); //100
    		console.log(b); //200
    	}
    	fn();
    	//例子
    	var a = 100;
    	function F1(){
    		var b = 200;
    		function F2(){
    			var c = 300;
    			console.log(a); //100 //自由变量
    			console.log(b); //200 //自由变量
    			console.log(c); //300
    		}
    		F2();
    	}
    	F1();
    
    
    
    /*闭包*/
    	function F1(){
    		var a = 100;
    
    		//返回一个函数(函数作为返回值)
    		return function(){
    			console.log(a);
    		}
    	}
    	//f1得到一个函数
    	var f1 = F1();
    	var a = 200;
    	f1();
    	//f1执行的是return里的函数,return里的a是个自由变量,要去父级作用域寻找,父级作用域F1里面定义了a,所以打印出来的a的值是100.
    	/*闭包的使用场景
    	1、函数作为返回值(上一个demo)
    	2、函数作为函数传递(下面这个例子)
    	*/
    	function F1(){
    		var a = 100;
    		return function(){
    			console.log(a);
    		}
    	}
    	var f1 = F1();
    	function F2(fn){
    		var a = 200;
    		fn();
    	}
    	F2(f1);
    

    解题:

    说一下对变量提升的理解 

    变量定义
    函数声明(注意和函数表达式的区别)
    执行上下文的概念。
    各个函数中,它的变量的声明和定义,以及函数的声明都会提前,放在前面,由此就是变量提升主观上、形象上的理解。

    说明this几种不同的使用场景

    作为构造函数执行

    作为对象属性执行

    作为普通函数执行

    call、apply、bind

    创建10个<a>标签,点击时弹出对应的序号

    var i;
    for(i=0;i<10;i++){
    	(function(i){
    		var a = document.createElement('a');
    		a.innerHTML = i+'<br>';
    		a.addEventListener('click',function(e){
    			e.preventDefault();
    			alert(i);
    		})
    		document.body.appendChild(a);
    	})(i);
    }

    如何理解作用域

    要领:
    1、自由变量
    2、作用域链,即自由变量的查找
    3、闭包的两个场景

    实际开发中闭包的应用

    //闭包实际应用中主要用于封装变量,收敛权限
    	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
    	firstLoad(20); //true

    //在 isFirstLoad 函数外面,根本不可能修改掉 _list 的值

      

    四、异步和单线程

    题目: 

    • 同步和异步的区别是什么?分别举一个同步和异步的例子
    • 一个关于setTimeout的笔试题
    • 前端使用异步的场景有哪些

    知识点:

    /*什么是异步(对比同步)*/
    	//同时执行,不会阻塞程序执行
    	console.log(100);
    	setTimeout(function(){
    		console.log(200);
    	},1000);
    	console.log(300);
    	setTimeout(function(){
    		console.log(400);
    	},1000);
    	//下面这个例子类似同步
    	console.log(100);
    	alert(200);
    	console.log(300);
    
    
    
    /*前端使用异步的场景*/
    	/*何时需要异步:
    	在可能发生等待的情况
    	等待过程中不能像alert一样阻塞程序进行
    	因此,所有的“等待的情况”都需要异步
    	1、定时任务:setTimeout、setInterval
    	2、网络请求:ajax请求、动态<img>加载
    	3、事件绑定
    	*/
    	//ajax请求代码示例
    	console.log('start');
    	$.get('./data1.json',function(data1){
    		console.log(data1);
    	})
    	console.log('end');
    	//<img>加载示例
    	console.log('start');
    	var img = document.createElement('img');
    	img.onload = function(){
    		console.log('loaded');
    	}
    	img.src = '/xxx.png';
    	console.log('end');
    	//事件绑定示例
    	console.log('start');
    	document.getElementById('btn1').addEventListener('click',function(){
    		alert('clicked');
    	})
    	console.log('end');
    	
    
    
    
    /*异步和单线程*/
    	console.log(100);
      setTimeout(function(){
        console.log(200);
      });
      console.log(300);
      //执行结果:100、300、200
      //setTimeout是异步,最后执行。这个例子的setTimeout没有等待时间,所以待其它执行完之后立马执行setTimeout。
      //单线程就是一次只能做一件事
      /*解析:
      1、执行第一行,打印100
      2、执行setTimeout后,传入setTimeout的函数会被暂存起来,不会立即执行(单线程的特点,不能同时干两件事)
      3、执行最后一行,打印300
      4、待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行。
      5、发现暂存起来的setTimeout中的函数无需等待时间,就立即拿过来执行。
      */
    

    解题:

    同步和异步的区别是什么?分别举一个同步和异步的例子

    同步会阻塞代码执行,而异步不会。
    alert是同步,setTimeout是异步。

    例子:

    //异步
    	console.log(100);
    	setTimeout(function(){
    		console.log(200);
    	},1000);
    	console.log(300);
    //同步
    	console.log(100);
    	alert(200);
    	console.log(300);

    一个关于setTimeout的笔试题

    console.log(1);
      setTimeout(function(){
        console.log(2);
      },0)
      console.log(3);
      setTimeout(function(){
        console.log(4);
      },1000)
      console.log(5);
      
      //1 3 5 2 4

    前端使用异步的场景有哪些  

    1. 定时任务:setTimeout、setInterval
    2. 网络请求:ajax请求、动态<img>加载
    3. 事件绑定

    五、其它知识点

    题目:

    • 获取2017-06-10格式的日期
    • 获取随机数,要求是长度一致的字符串格式
    • 写一个能遍历对象和数组的通用forEach函数

    知识点: 

    /*日期*/
     Date.now(); //获取当前时间毫秒数
     var dt = new Date();
     dt.getTime(); //获取毫秒数
     dt.getFullYear(); //年
     dt.getMonth(); //月(0-11)
     dt.getDate(); //日(0-31)
     dt.getHours(); //小时(0-23)
     dt.getMinutes(); //分钟(0-59)
     dt.getSeconds(); //秒(0-59)
    
    
    
    /*Math*/
    	Math.random(); //获取随机数。(返回的是 >0 和 <1 的小数)。有清除缓存的作用。
    
    
    
    /*数组API*/
    	//forEach //遍历所有元素
    	var arr = [1,2,3];
    	arr.forEach(function(item,index){
    		//遍历数组的所有元素。item:元素的值。index:元素的位置
    		console.log(index,item);
    	})
    	//every   //判断所有元素是否都符合条件
    	var arr = [1,2,3];
    	// var arr = [1,2,3,4,5]; 
    	var result = arr.every(function(item,index){
    		if(item<4){
    			return true;
    		}
    	})
    	console.log(result); //true
    	//some    //判断是否有至少一个元素符合条件
    	var arr = [1,2,3];
    	var result = arr.some(function(item,index){
    		if(item<2){
    			return true;
    		}
    	})
    	console.log(result); //true
    	//sort    //排序
    	var arr = [1,4,2,5,3];
    	var arr2 = arr.sort(function(a,b){
    		//从小到大排序
    		return a -b;
    
    		//从大到小排序
    		//return b-a;
    	})
    	console.log(arr2);
    	//map     //对元素重新组装,生成新数组
    	var arr = [1,2,3,4];
    	var arr2 = arr.map(function(item,index){
    		return '<b>' + item + '</b>';
    	})
    	console.log(arr2);
    	//filter  //过滤符合条件的元素
    	var arr = [1,2,3,4];
    	var arr2 = arr.filter(function(item,index){
    		if(item>=2){
    			return true;
    		}
    	})
    	console.log(arr2);
    
    
    
    /*对象API*/
    	var obj = {
    		x:100,
    		y:200,
    		z:300
    	}
    	var key;
    	for(key in obj){ //key是obj的属性名
    		//注意这里的 hasOwnProperty ,再讲原型链时候讲过了
    		if(obj.hasOwnProperty(key)){ //判断key是obj原生的属性,而不是原型里面的属性
    			console.log(key,obj[key]);
    		}
    	}

    解题:

    获取2017-06-10格式的日期

    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 = new Date();
    var formatDate = formatDate();
    console.log(formatDate);

    获取随机数,要求是长度一致的字符串格式

    var random = Math.random();
    var random = random + '0000000000'; //后面加上10个零,为了确保长度一致
    var random = random.slice(0,10); //截取前10位
    console.log(random);

    写一个能遍历对象和数组的通用forEach函数

    function forEach(obj,fn){
        var key;
        if(obj instanceof Array){
          //准确判断是不是数组
          obj.forEach(function(item,index){
            fn(index,item);
          })
        }else{
          //不是数组就是对象,对象用for in循环
          for(key in obj){
            fn(key,obj[key]);
          }
        }
      }
      var arr = [1,2,3]; 
      //注意,这里参数的顺序换了,为了和对象的遍历格式一致
      forEach(arr,function(index,item){
        console.log(index,item);
      })
      var obj = {x:100,y:200};
      forEach(obj,function(key,value){
        console.log(key,value);
      })
    

     

     

  • 相关阅读:
    Linux磁盘管理之创建磁盘分区05
    Linux磁盘管理之设备文件详解04
    Linux命令行上传文件到百度网盘
    Linux磁盘管理之元数据、文件和目录、链接文件03
    std..tr1如何传递引用类型给function
    如何判断一个点是否在矩形之内及C++的操作符重载
    C++11中部分新语法说明
    物理引擎中基于AABB碰撞盒的SAP碰撞检测
    c++动态库中对于字符类型变量的格式化处理
    从tr1中function使用看converting constructor
  • 原文地址:https://www.cnblogs.com/chenglu/p/7290728.html
Copyright © 2011-2022 走看看