面面试,收获真的挺大的,感谢能有此次机会,感受打开了前进的路, 建议看到题后本身先写一下试试,知其然还需知其因此然,把原理搞明白javascript
let str = 'abc'
function rev(str) {
let arr = str.split('')
let tem = []
for (let i = arr.length-1; i >= 0; i--) {
tem.push(arr[i])
}
return tem.join('')
}
rev(str)
console.log(rev(str))
复制代码
// 冒泡排序: 随便拿出一个数与后者比较,若是前者比后者大,那么二者交换位置,
let arr = [5,2,3,1,4]
function bubbleSort(arr) {
let arrLen = arr.length
for (let i = 0; i < arrLen; i++){
for (let j = i; j < arrLen; j++){
let tempi = arr[i];
let tempj = arr[j];
if (tempi > tempj) {
arr[i] = tempj;
arr[j] = tempi;
}
}
}
return arr
}
console.log(bubbleSort(arr))
/* 快速排序 :
* 1. 以一个数为基准(基准值能够任意选择,选择中间的值容易理解
* 2. 按照顺序,将每一个元素与"基准"进行比较,造成两个子集,一个"小于3",另外一个"大于等于3"。
* 3. 对两个子集不断重复第一步和第二步,直到全部子集只剩下一个元素为止
*/
let arr = [5, 2, 3, 1, 4]
function quickSort(arr) {
// 若是数组为1那就不必比较了
 if (arr.length <= 1) { return arr }
// 取中间索引值
let pivotIndex = Math.floor(arr.length / 2)
// 获取中间值
let pivot = arr.splice(pivotIndex, 1)[0]
let left = []
let right = []
for (let i = 0; i < arr.length; i ++) {
if(arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
// 使用递归不断重复这个过程
return quickSort(left).concat([pivot], quickSort(right))
}
console.log(quickSort(arr))
复制代码
// 1. from && set
let arr = [1, 1, 4, 50, 50, 6, 2, 2]
let res = Array.from(new Set(arr))
console.log(res)
// 2. filter && indexOf
let arr = [2, 2, 33, 44, 33]
let res = arr.filter((item, index, arr) => {
return arr.indexOf(item) == index
})
console.log(res)
// 3. forEach && includes
let arr = [2, 2, 33, 44, 33]
let res = []
arr.forEach((item) => {
if (!res.includes(item)) {
res.push(item)
}
})
console.log(res)
// 4. filter && Map
let arr = [2, 2, 33, 44, 33]
const tem = new Map();
let res = arr.filter((item) => !tem.has(item) && tem.set(item, 1))
console.log(res)
复制代码
let str = ' adb ddd '
let res = str.replace(/\s+/g, "")
console.log(res)
复制代码
let str = 'asdasddsfdsfadsfdghdadsdfdgdasd';
function getMax(str) {
let obj = {};
for (let i in str) {
if (obj[str[i]]) {
obj[str[i]]++
} else {
obj[str[i]] = 1
}
}
let num = 0
let number = 0
for (var i in obj) {
//若是当前项大于下一项
if (obj[i] > num) {
//就让当前值更改成出现最屡次数的值
num = obj[i]
number = i
}
}
console.log('最多的值是' +number+ '出现次数为' + num);
}
getMax(str);
复制代码
// 构造函数继承
function Super(){
this.name = ["张三","李四"]
}
function Sub(){
Super.call(this)
}
let a = new Sub();
a.name.push("王五")
// “张三","李四","王五" console.log(a.name); let b = new Sub() //// “张三","李四"
console.log(b.name)
// Class 继承
class Fathter {
constructor(name) {
this.name = name
}
hello() {
console.log('Hello, ' + this.name)
}
}
class Son extends Fathter {
constructor(name) {
// 记得用super调用父类的构造方法
super(name)
console.log(name)
}
}
let res = new Son('张三')
res.hello()
复制代码
JSON.parse(JSON.stringify(obj));
复制代码
function Foo(){
getName = function () {
console.log(1);
}
return this;
}
Foo.getName = function() {
console.log(2);
};
Foo.prototype.getName = function(){
console.log(3);
};
var getName = function(){
console.log(4);
};
function getName(){
console.log(5)
};
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3 至关于 var f = new Foo() f.getName()
new new Foo().getName(); // 3
// 这道题至关经典了 花点时间本身去看下吧
复制代码
function fun() {
this.a = 0
this.b = function() {
console.log(this)
console.log(this.a)
}
}
fun.prototype = {
b: function() {
this.a = 20
console.log(this.a)
},
c: function() {
this.a = 30
console.log(this.a)
}
}
var my_fun = new fun();
//私有方法 this=>my_fun
my_fun.b();
console.log(my_fun.a);
//公有方法 this=>my_fun this.a = 30(私有属性a修改成30)
my_fun.c();
console.log(my_fun.a);
var my_fun2 = new fun();
console.log(my_fun2.a);
//this=>my_fun2.__proto__ 当前实例·经过原型链在共有属性增长的了一a:30
my_fun2.__proto__.c();
console.log(my_fun2.a);
console.log(my_fun2.__proto__.a);
// 0,0,30,30,0,30,0,30
复制代码
function setName(obj){
obj.name = "Tom"
obj = new Object()
obj.name = 'Mike'
}
var person = new Object()
setName(person)
console.log(person.name) // "Tom"
复制代码
// ES5 的写法
let arr = [ 2,4,5,1]
console.log(Math.min.apply(null, arr))
// ES6 的写法
console.log(Math.max(...[14, 3, 77, 30]))
复制代码
let num = 12345678
console.log(num.toLocaleString())
复制代码
let num = 12345678
function toThousands(num) {
var result = '', counter = 0;
num = (num || 0).toString();
for (var i = num.length - 1; i >= 0; i--) {
counter++;
result = num.charAt(i) + result;
if (!(counter % 3) && i != 0) { result = ',' + result; }
}
return result;
}
console.log(toThousands(num))
复制代码
// 3-1
let num = 12345678
function toThousands(num) {
return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
}
console.log(toThousands(num))
// 3-2
let num = 12345678
function toCurrency(num){
var parts = num.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
}
console.log(toCurrency(num))
复制代码
相关连接前端
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
console.log(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
复制代码
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
console.log(object.getNameFunc()()); // the window
复制代码
var length = 1
function fn() {
console.log(this.length)
}
var obj = {
length: 3,
me:function(fn){
fn() // 1
arguments[0]() // 2
}
}
obj.me(fn, 1)
复制代码
let str = '你好,abc'
function getLength(str){
let length = 0
let reg = /[\u4e00-\u9fa5]/
for (let i = 0; i < str.length; i++) {
if (reg.test(str.charAt(i))) {
length +=2
} else {
length ++
}
}
return length
}
console.log(getLength(str))
复制代码
利用 Proxyvue
参考 -- 摒弃 Object.defineProperty,基于 Proxy 的观察者机制探索java
prototype是构造函数的属性。node
proto 是每一个实例都有的属性,能够访问 [[prototype]] 属性。webpack
实例的__proto__ 与其构造函数的prototype指向的是同一个对象。ios
function Student(name) {
this.name = name;
}
Student.prototype.setAge = function(){
this.age=20;
}
let Jack = new Student('jack');
console.log(Jack.__proto__);
//console.log(Object.getPrototypeOf(Jack));;
console.log(Student.prototype);
console.log(Jack.__proto__ === Student.prototype);//true
。
复制代码
参考刘小夕解答git
var a = {n:1};
var b = a; // 持有a,以回查
a.x = a = {n:2};
console.log(a.x);// --> undefined
console.log(b.x);// --> {n:2}
复制代码
var y = 1;
if (function f(){}) {
y += typeof f;
}
console.log(y); // 1undefined
复制代码
var a = 0
function b(){
console.log(a) // fun a
a = 10
console.log(a) // 10
return;
function a(){}
}
b()
console.log(a) // 0
复制代码
概念:
1. 在事件被触发n秒后再执行回调,若是在这n秒内又被触发,则从新计时。
2. 屡次触发事件后,事件处理函数只执行一次,而且是在触发操做结束时执行。
应用场景:
1. 文本输入的验证(连续输入文字后发送 ajax 请求进行验证,验证一次就好)
2. 给按钮加函数防抖防止表单屡次提交。
生活实例:
若是有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时若是又有人进电梯了(在10秒内再次触发该事件),咱们又得等10秒再出发(从新计时)。
代码
function debounce(func, interval = 100){
let timer;
return (...args) => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
func.apply(func, args);
}, interval);
}
}
复制代码
概念:
规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,若是在同一个单位时间内某事件被触发屡次,只有一次能生效
应用场景:
滚动刷新如 touchmove, mousemove, scroll。
生活实例:(实例忘记参考谁的了,看到我添加链接)
1. 咱们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会造成一个连贯的动画,因此在电影的播放(之前是,如今不知道)中基本是以每秒 24 张的速度播放的,为何不 100 张或更可能是由于 24 张就能够知足人类视觉需求的时候,100 张就会显得很浪费资源
2. 假设电梯一次只能载一人的话,10 我的要上楼的话电梯就得走 10 次,是一种浪费资源的行为;而实际生活正显然不是这样的,当电梯里有人准备上楼的时候若是外面又有人按电梯的话,电梯会再次打开直到满载位置,从电梯的角度来讲,这时一种节约资源的行为(相对于一次只能载一我的)。。
代码
function throttle(fn, interval = 100) {
let canRun = true; // 经过闭包保存一个标记
return (...args) => {
if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
canRun = false; // 当即设置为false
setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
fn.apply(fn, args)
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示能够执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
canRun = true;
}, interval);
};
}
复制代码
function foo(a) {
var a;
return a;
}
function bar(a) {
var a = 'bye';
return a;
}
[foo('hello'), bar('hello')] // hello bye
// 在两个函数里, a做为参数其实已经声明了, 因此 var a; var a = 'bye' 其实就是 a; a ='bye'
复制代码
原型链解决的主要是继承问题。
每一个对象拥有一个原型对象,经过 proto (读音: dunder proto) 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null(==Object.proptotype.proto 指向的是null==)。这种关系被称为原型链 (prototype chain),经过原型链一个对象能够拥有定义在其余对象中的属性和方法。 构造函数 Parent、Parent.prototype 和 实例 p 的关系以下:(==p.proto === Parent.prototype==)
var name = "World!";
(function() {
if(typeof name=== 'undefined'){
var name='Jack';
console.log('Goodbye'+name);
} else {
console.log('hello'+name);
}
})()
// Goodbye Jack
复制代码
跳到 n 阶假设有 f(n)种方法。
往前倒退,若是青蛙最后一次是跳了 2 阶,那么以前有 f(n-2)种跳法; 若是最后一次跳了 1 阶,那么以前有 f(n-1)种跳法。
因此:f(n) = f(n-1) + f(n-2)。就是斐波那契数列
复制代码
参考
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor
return this.newColor
}
constructor({ newColor = 'green' } = {}) {
this.newColor = newColor
}
}
const freddie = new Chameleon({ newColor: 'purple' })
freddie.colorChange('orange')
// 会报错
colorChange是一个静态方法。静态方法被设计为只能被建立它们的构造器使用(也就是 Chameleon),而且不能传递给实例。由于 freddie 是一个实例,静态方法不能被实例使用,所以抛出了 TypeError 错误。
复制代码
function* generator(i) {
yield i;
yield i * 2;
}
const gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 20
通常的函数在执行以后是不能中途停下的。可是,生成器函数却能够中途“停下”,以后能够再从停下的地方继续。当生成器遇到yield关键字的时候,会生成yield后面的值。注意,生成器在这种状况下不 返回 (return )值,而是 生成 (yield)值。
首先,咱们用10做为参数i来初始化生成器函数。而后使用next()方法一步步执行生成器。第一次执行生成器的时候,i的值为10,遇到第一个yield关键字,它要生成i的值。此时,生成器“暂停”,生成了10。
而后,咱们再执行next()方法。生成器会从刚才暂停的地方继续,这个时候i仍是10。因而咱们走到了第二个yield关键字处,这时候须要生成的值是i*2,i为10,那么此时生成的值即是20。因此这道题的最终结果是10,20。
复制代码
const num = parseInt("7*6", 10);
console.log(num) // 7
parseInt检查字符串中的字符是否合法. 一旦遇到一个在指定进制中不合法的字符后,当即中止解析而且忽略后面全部的字符。
复制代码
function create(proto) {
function F() {};
F.prototype = proto;
F.prototype.constructor = F;
return new F();
}
复制代码
zhangxiang958-理解 ES6 generator
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id='app'>
<h3>姓名</h3>
<p>{{name}}</p>
<h3>年龄</h3>
<p>{{age}}</p>
</div>
</body>
</html>
<script>
document.addEventListener('DOMContentLoaded', function(){
let opt = {el:'#app', data:{name:'检索中...', age:30}}
let vm = new Vue(opt)
setTimeout(() => {
opt.data.name = '王永峰'
}, 2000);
}, false)
class Vue{
constructor(opt){
this.opt = opt
this.observe(opt.data)
let root = document.querySelector(opt.el)
this.compile(root)
}
// 为响应式对象 data 里的每个 key 绑定一个观察者对象
observe(data){
Object.keys(data).forEach(key => {
let obv = new Observer()
data["_"+key] = data[key]
// 经过 getter setter 暴露 for 循环中做用域下的 obv,闭包产生
Object.defineProperty(data, key, {
get(){
Observer.target && obv.addSubNode(Observer.target);
return data['_'+key]
},
set(newVal){
obv.update(newVal)
data['_'+key] = newVal
}
})
})
}
// 初始化页面,遍历 DOM,收集每个key变化时,随之调整的位置,以观察者方法存放起来
compile(node){
[].forEach.call(node.childNodes, child =>{
if(!child.firstElementChild && /\{\{(.*)\}\}/.test(child.innerHTML)){
let key = RegExp.$1.trim()
child.innerHTML = child.innerHTML.replace(new RegExp('\\{\\{\\s*'+ key +'\\s*\\}\\}', 'gm'),this.opt.data[key])
Observer.target = child
this.opt.data[key]
Observer.target = null
}
else if (child.firstElementChild)
this.compile(child)
})
}
}
// 常规观察者类
class Observer{
constructor(){
this.subNode = []
}
addSubNode(node){
this.subNode.push(node)
}
update(newVal){
this.subNode.forEach(node=>{
node.innerHTML = newVal
})
}
}
</script>
复制代码
提取公共模块,区分开发环境,移除重复没必要要的 css 和 js 文件等方面说。
使用 v-for更新已渲染的元素列表时,默认用就地复用策略。列表数据修改的时候,他会根据key值去判断某个值是否修改:若是修改,则从新渲染这一项;不然复用以前的dom,仅修改value值。
函数式组件,即无状态,没法实例化,内部没有任何生命周期处理方法,很是轻量,于是渲染性能高,特别适合用来只依赖外部数据传递而变化的组件。
关于 Vue 编译原理这块的总体逻辑主要分三个部分,也能够说是分三步,这三个部分是有先后关系的:
该题是遇到问题最多的 根据自身状况回答
vw: 兼容性问题 ios八、安卓4.4及以上才彻底支持
rem:和根元素font-size值强耦合,系统字体放大或缩小时,会致使布局错乱;弊端之二:html文件头部需插入一段js代码
重绘和回流是渲染步骤中的一小节,可是这两个步骤对于性能影响很大。
回流一定会发生重绘,重绘不必定会引起回流。回流所需的成本比重绘高的多,改变深层次的节点极可能致使父节点的一系列回流。
重绘和回流其实和 Event loop 有关
Load 事件触发表明页面中的 DOM,CSS,JS,图片已经所有加载完毕。
DOMContentLoaded 事件触发表明初始的 HTML 被彻底加载和解析,不须要等待 CSS,JS,图片加载。
因为用户访问源站业务有性能瓶颈,经过cdn技术把源站的内容缓存到多个节点。用户向源站域名发起请求时,请求会被调度至最接近用户的服务节点,直接由服务节点直接快速响应,有效下降用户访问延迟,提高可用性。
参考import、require、export、module.exports 混合使用详解
/* 浮动布局 */
.layout.float .left{
float:left;
width:300px;
background: red;
}
.layout.float .center{
background: yellow;
}
.layout.float .right{
float:right;
width:300px;
background: blue;
}
/* 绝对定位布局 */
.layout.absolute .left-center-right>div{
position: absolute;
}
.layout.absolute .left{
left:0;
width: 300px;
background: red;
}
.layout.absolute .center{
left: 300px;
right: 300px;
background: yellow;
}
.layout.absolute .right{
right:0;
width: 300px;
background: blue;
}
/* flex布局 */
.layout.flexbox{
margin-top: 110px;
}
.layout.flexbox .left-center-right{
display: flex;
}
.layout.flexbox .left{
width: 300px;
background: red;
}
.layout.flexbox .center{
flex:1;
background: yellow;
}
.layout.flexbox .right{
width: 300px;
background: blue;
}
复制代码
按照固定宽高和不固定宽高分类各说几个方法