前端社招(一年经验)面经一

一、 var、let和const的区别?

①var声明的变量会挂载在window上,而let和const声明的变量不会

var a = 100;
console.log(a,window.a);    // 100 100

let b = 10;
console.log(b,window.b);    // 10 undefined

const c = 1;
console.log(c,window.c);    // 1 undefined

②var声明变量存在变量提升,let和const不存在变量提升

console.log(a); // undefined  ===>  a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined  ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined  ===> 找不到c这个变量
const c = 10;

③let和const声明形成块作用域,而var声明的变量作用域为函数作用域或全局作用域

if(1){
    var a = 100;
    let b = 10;
    const c = 1;
}
console.log(a); // 100
console.log(b)  // 报错:b is not defined  ===> 找不到b这个变量
console.log(c)  // 报错:c is not defined  ===> 找不到c这个变量

④同一作用域下let和const不能声明同名变量,而var可以

var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10

let a = 100;
let a = 10;
//  控制台报错:Identifier 'a' has already been declared  ===> 标识符a已经被声明了。

⑤const一旦声明必须赋值,不能使用null占位;声明后不能再修改;如果声明的是复合类型数据,可以修改其属性

const a;//报错
const a = 100; //一旦声明必须赋值,不能使用null占位

const a = 100;
a = 10;//报错,声明后不能再修改

const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'},如果声明的是复合类型数据,可以修改其属性

⑥暂存死区

var a = 100;

if(1){
    a = 10;
    //在当前块作用域中存在a使用let/const声明的情况下,给a赋值10时,只会在当前作用域找变量a,
    // 而这时,还未到声明时候,所以控制台Error:a is not defined
    let a = 1;
}

二、ES5与ES6数组去重?

1.ES5数组去重:使用indexOf(可返回某个指定的字符串值在字符串中首次出现的位置,如果首次出现,返回-1)

var arr = [1,2,3,1,3,4,5];
	Array.prototype.myInfo = function(){
		var newArr = [];
		for(var i=0;i<arr.length;i++){
			var a = newArr.indexOf(arr[i]);
			if(a == -1){
				newArr[newArr.length] = arr[i];
			}
		}
		return newArr;
	}
	var result = arr.myInfo();
	console.log(result);

2.ES6数组去重
(1)Set和Array.from
①ES6中新增了Set数据结构,类似于数组,但是它的成员都是唯一的
,其构造函数可以接受一个数组作为参数

let array = [1, 1, 1, 1, 2, 3, 4, 4, 5, 3];
let set = new Set(array);
console.log(set);
// => Set(5)  [1, 2, 3, 4, 5]

②ES6中Array新增了一个静态方法Array.from,可以把类似数组的对象转换为数组

let set = new Set();
set.add(1).add(2).add(3);
let array = Array.from(set);
console.log(array);
// => Array(3)  [1, 2, 3]

③于是,现在我们可以用一行代码实现数组去重

let array = Array.from(new Set([1, 1, 1, 2, 3, 2, 4]));
console.log(array);
// => Array(4)  [1, 2, 3, 4]

(2)Set和rest
rest 方法操作符为“…”;… 将字符从数组中剥离出来

let arr = [1,2,1,2,3];
let result = new Set(arr);

console.log(result); 	// => Set(3)  [1, 2, 3]
console.log(...result); // => 1, 2, 3
console.log([...result]); // => Array(3)  [1, 2, 3]

console.log([...new Set(arr)]);	// => Array(3)  [1, 2, 3]

三、vue的生命周期?父子组件生命周期?

Vue实例需要经过创建、初始化数据、编译模板、挂载DOM、渲染、更新、渲染、卸载等一系列过程,这个过程就是Vue的生命周期,Vue中提供的钩子函数有beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
父子组件嵌套时,父组件和子组件各拥有各自独立的钩子函数。
1.创建过程
创建过程主要涉及beforeCreate、created、beforeMount、mounted四个钩子函数。

父beforeCreate ->父Created -> 父BeforeMount ->子BeforeCreate ->子Created ->子BeforeMount ->子Mounted ->父Mounted

2.更新过程
更新过程主要涉及beforeUpdate、updated两个钩子函数,当父子组件有数据传递时才会有生命周期的比较。

父BeforeUpdate ->子BeforeUpdate ->子Updated ->父Updated

3.销毁过程
销毁过程主要涉及beforeDestroy、destroyed两个钩子函数,本例直接调用vm.$destroy()销毁整个实例以达到销毁父子组件的目的。

父BeforeDestroy ->子BeforeDestroy ->子Destroyed ->父Destroyed

四、微信小程序页面跳转接口?

(1)wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到tabbar页面

onLoad: function(options) {
      wx.navigateTo({
             url: '../index/index'
      })
}

(2)wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不能跳转到tabbar页面
(3)wx.navigateBack():关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages()获取当前的页面栈,决定需要返回几层

onLoad: function(options) {
        var pages = getCurrentPages()
        var num = pages.length
        navigateBack:function(){
            wx.navigateBack({
                 delta: num
            })
        }
 }

(4)wx.switchTab():跳转到tabBar页面,并关闭其他所有非tabBar页面
(5)wx.reLaunch():关闭所有页面,打开到应用内的某个页面
拓展1:wx.navigateTo和wx.redirectTo有什么区别?分别适用什么场景?
①使用wx.navigateTo每新开一个页面,页面栈大小加1,使用wx.navigateTo重复打开页面也会增加页面栈。
②使用wx.redirectTo会关闭当前页面打开新页面,页面栈大小不变
③对于可逆操作,使用wx.navigateTo,比如从首页跳转到二级页面,从二级页面返回是不需要重新渲染首页。
④对于不可逆操作,使用wx.redirectTo,比如用户登录成功后,关闭登录页面,不能返回到登录界面。
⑤不要在首页使用wx.redirectTo,这样会导致应用无法返回首页。
拓展2:页面携带数据跳转
①方法1:API跳转页面时携带参数,在目标页面通过options.获取数据复制给本地变量
test1页面

// pages/test1/test1.js
Page({
 
  /**
   * 页面的初始数据
   */
  data: {
    name:'Tom',
    age:'12'
   
  },
 
  buttonListener:function(){
    var that = this
    wx.navigateTo({
      url: '/pages/test2/test2?nameData=' + that.data.name + '&ageData=' + that.data.age
    })
  }
})
 
<!--pages/test1/test1.wxml-->
<view>
<text>姓名:{{name}}</text>
</view>
<view>
<text>年龄:{{age}}</text>
</view>
<button bindtap='buttonListener'>携带数据跳转</button>

test2页面

// pages/test2/test2.js
Page({
 
  /**
 * 页面的初始数据
   */
  data: {
    name:null,
    age:null
   
  },
 
  /**
 * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    var that = this
    that.setData({
      name:options.nameData,
      age:options.ageData
    })
   
  }
})
 
<!--pages/test2/test2.wxml-->
<view>
<text>姓名为:{{name}}</text>
</view>
<view>
<text>年龄为:{{age}}</text>
</view>

test1页面:

  • Button点击事件:案例中采用了点击button触发跳转事件,所以要为button添加一个监听函数。在test1.wxml页面的中添加bindTap属性,来命名该button的监听函数名称。然后在test1.js中实现该监听函数即可
  • 跳转函数:微信小程序提供自带的页面跳转函数,具体可参考微信小程序API

test2页面:

  • 接收数据:使用onLoad函数在加载页面时接收数据,通过options.数据a的名称来获取数据a的内容,并赋值给本地变量

②方法2:使用全局数据存储
将要传递的数据,存储在App对象上(比如globalData属性)。
将要传递的数据,存储在小程序的本地数据缓存(Storage)中。
例如,我们在将要退出页面B的时候,作如下调用:

//=== 1. 存储到app对象上的方式 ========
var app = getApp()
app.globalData.mydata = {a:1, b:2};  //存储数据到app对象上
wx.navigateBack();  //返回上一个页面

//=== 2.存储到数据缓存的方式 =========
wx.setStorage({
  key: "mydata",
  data: {a:1, b:2},
  success: function () {
    wx.navigateBack();   //返回上一个页面
  }
})

这样一来,当返回到上一个页面的时候,可以通过读取这些全局存储区域,来获取到我们需要的数据。
不过,这种方式也是有很明显的缺点的。由于是全局数据存储,所以当你存入了那些数据后,必须谨慎的去管理这些全局数据(何时被销毁),否则一不小心,就会产生副作用。

③方法3:从页面路由栈中直接获取和操作目标Page对象
这种方式,是通过调用小程序的API:getCurrentPages(),来获取当前页面路由栈的信息,这个路由栈中按照页面的路由顺序存放着相应的Page对象,我们可以很容易的获取到上一级页面的完整Page对象
,从而使直接调用Page对象的属性和方法成为可能。如下所示:

var pages = getCurrentPages();
var currPage = pages[pages.length - 1];   //当前页面
var prevPage = pages[pages.length - 2];  //上一个页面

//直接调用上一个页面的setData()方法,把数据存到上一个页面中去
prevPage.setData({
  mydata: {a:1, b:2}
})

比起全局数据存储的方式,这种方式在逻辑上要清晰得多,也不存在对数据的销毁有额外的管理工作。

五、冒泡排序?

冒泡排序算法的原理如下:

  1. 比较相邻的元素,如果第一个比第二个大,就交换他们。
  2. 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

js实现冒泡排序

// 封装成函数
function bubble(arr){
    if(arr instanceof Array && arr.length > 1){
        //外层循环,控制趟数,每一次找到一个最大值
         for (var i = 0; i < arr.length - 1; i++) {
            // 内层循环,控制比较的次数,并且判断两个数的大小
            for (var j = 0; j < arr.length - 1 - i; j++) {
                // 如果前面的数大,放到后面(从小到大的冒泡排序)
                if (arr[j] > arr[j + 1]) {
                    var temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        return arr;  // 将执行完的结果返回就可以
    }
}

var arr = [3,5,1,2,9,8,4,5,3,4]; 
console.log(bubble(arr)); // [1, 2, 3, 3, 4, 4, 5, 5, 8, 9]

拓展1:十大排序算法的时间复杂度与空间复杂度
在这里插入图片描述

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
  • 内排序:所有排序操作都在内存中完成;
  • 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
  • 时间复杂度:一个算法执行所耗费的时间。
  • 空间复杂度:一个算法在运行过程中临时占用存储空间大小。

拓展2:快速排序
快速排序是对冒泡排序的一种改进,它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

function quickSort(arr){
    if(arr.length<=1){
        return arr;
    }
    var left = [],
        right = [],
        pivot = arr.splice(0, 1)[0];
        for(var i = 0;i<arr.length;i++){
            if(arr[i]>pivot){
                right.push(arr[i]);
            }else{
                left.push(arr[i]);
            }
        }
    return quickSort(left).concat([pivot],quick(right));
}

六、24点游戏算法?

描述:输入1-10的任意四个数(可以重复),通过加减乘除得到24。
解决方法:

穷举法:
①穷举四个数的位置组合 (a b c d) (a b d c) (...)
②穷举标点符号组合 (a+b+c+d) (a+b+c-d) (...)
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值