JS原生基础面试题 _ 不断更新

24 、GET系列和POST系列的本质区别 ?javascript

  1. GET传递给服务器的内容比POST少,由于URL有最长大小限制(IE浏览器通常限制2KB,谷歌浏览器通常限制4~8KB,超过长度的部分自动被浏览器截取了)
xhr.open('GET','/list?name=zhufeng&year=10&xxx=xxx...')
xhr.send('....')  请求主体中传递的内容理论上没有大小限制,可是真实项目中,为了保证传输的速度,咱们会本身限制一些
复制代码
  1. GET会产生缓存(缓存不是本身可控制的):由于请求的地址(尤为是问号传递的信息同样),浏览器有时候会认为你要和上次请求的数据同样,拿的是上一次信息;这种缓存咱们不指望有,咱们指望的缓存是本身可控制的;因此真实项目中,若是一个地址,GET请求屡次,咱们要去除这个缓存;
//=>解决办法设置随机数
xhr.open('GET','/list?name=zhufeng&_='+Math.random());
...
xhr.open('GET','/list?name=zhufeng&_='+Math.random());
复制代码
  1. GET相比较POST来讲不安全:GET是基于问号传参传递给服务器内容,有一种技术叫作URL劫持,这样别人能够获取或者篡改传递的信息;而POST基于请求主体传递信息,不容易被劫持;

2三、Http 状态码 301 和 302 的应用场景分别是什么html

301重定向是永久的重定向,搜索引擎在抓取新的内容的同时也将旧的网址替换为了重定向以后的网址。java

302重定向只是暂时的重定向,搜索引擎会抓取新的内容而保留旧的地址,由于服务器返回302,因此,搜索搜索引擎认为新的网址是暂时的。git

2二、函数的防抖节流有什么区别,怎么实现? 参考另外一篇文章 juejin.im/post/5d65cb…es6

2一、获取数组中的最大值和最小值, 你有几种办法github

let ary = [12, 24, 13, 8, 35, 15];

/* 解决方案一:先排序,第一项和最后一项就是咱们须要的 */
ary.sort(function (a, b) {
	return a - b;
});
let min = ary[0];
let max = ary[ary.length - 1];
console.log(min, max);


============
// 解决方案二: Math.max/Math.min 
//=>Math.max/min要求咱们传递的数据是一项项传递进来,获取一堆数中的最大最小,而不是获取一个数组中的最大最小
let min = Math.min([12, 24, 13, 8, 35, 15]);
console.log(min);//=>NaN
let min = Math.min(12, 24, 13, 8, 35, 15);
console.log(min); //=>8

1.基于ES6的展开运算符
let min = Math.min(...ary);
2.利用apply来实现便可(this无所谓,主要是利用apply给函数传参,须要写成一个数组的特征)
let min = Math.min.apply(Math, ary);

/* 解决方案三:假设法(假设第一个是最大的,让数组中的每一项分别和当前假设的值比较,若是比假设的值大,则把最大的值设为新的假设值,继续向后比较便可) */

let max = ary[0];
/* for (let i = 1; i < ary.length; i++) { let item = ary[i]; item > max ? max = item : null; } */
ary.forEach(item => {
	item > max ? max = item : null;
});
console.log(max); //=>35
复制代码

一、JS中的数据类型都有哪些?它们之间有什么区别?该如何检测?web

@数据类型算法

  • 基本数据类型: number、string、boolean、null、undefined
  • 引用数据类型: object(普通对象、数组对象、正则对象、日期对象、Math、实例、 prototype等)
  • function (普通函数和类)
  • 特殊数据类型:Symbol

@区别
基本数据类型按值操做 , 引用数据类型按照堆内存的引用地址来操做编程

@数据类型检测四种方式
typeof、instanceof、constructor、Object.prototype.toString.call()数组

二、经常使用浏览器的内核都有哪些?

webkit、Gecko、Trident、Presto等

三、数组中经常使用的迭代方法有哪些?都是什么意思?(至少四种)

forEach、map、find、some、filter、reduce、every、sort等

四、阐述一下let/var/const三者之间的区别?

let 和 var 的区别

  • 不存在变量提高
  • 不容许重复声明
  • 在全局做用域下设置变量不会给window设置属性
  • 存在块级做用域
  • 解决了一些暂时性死区问题

let 和 const 的区别
const 建立的是常量,存储的值不能被修改(准确说是不能修改变量的指 向)

五、阐述一下call/apply/bind三者之间的区别,以及应用场景?

一、 Function.prototype.apply和Function.prototype.call 的做用是同样的,区别在于传入参数的不一样;

  • 第一个参数:都是指定函数体内this的指向;
  • 第二个参数:开始不一样
    • apply:数组或者类数组;
    • call: 从第二个开始传入的参数是不固定的;

二、call 和 bind 的区别 call在改变函数this指向的时候,会把函数当即执行,而bind不会把函数立 即执行,只是预先处理了this和实参信息;

三、call比apply的性能要好,日常能够多用call , call传入参数的格式正是内部所须要的格式,尤为是es6 引入了 Spread operator (延展操做符) 后,即便参数是数组,可使用 call;
参考[call和apply的性能对比] (github.com/noneven/__/…)

四、真实项目中,咱们须要改变this指向的时候,会应用这三个方法,例如:

  • 给元素进行事件绑定,咱们须要把事件触发,所执行的函数中this和参数进 行预先处理,此时可使用bind进行处理;
  • 咱们能够基于call方法,让类数组借用数组原型上的方法,例如:把类数组 转换为数组
  • 能够基于apply传参是一个数组,借用Math.max获取数组中的最大值 ......

六、window.onload VS $(document).ready()

1.$(document).ready() 采用的是DOM2事件绑定,监听的是DOMContentLoaded这个事件,因此只要DOM结构加载完成就会被触发执行,并且同一个页面中可使用屡次(绑定不一样的方法,由于基于DOM2事件池绑定机制完成的)
2.window.onload必须等待全部资源都加载完成才会被触发执行,采用DOM0事件绑定,同一个页面只能绑定一次(一个方法),想绑定多个也须要改成window.addEventListener('load', function () {})DOM2绑定方式

七、.有A和B两个开发者,他们同时开发一款产品(最后的代码须要合并),为了防止相互以前产生变量污染,他们决定采用高级单例模式来进行模块化开发,请编写相应的代码示例!

// 开发者A
let AModule = (function () {
	let n = 10;
	let query = function () {
		//...
	};
	let fn = function () {
		//...
		//调取开发者B编写的QUERY方法
		BModule.query();
	};
	return {
		query: query,
		init: function () {
			query();
			fn();
		}
	}
})();

// 开发者B
let BModule = (function () {
	let n = 20;
	let query = function () {
		//...
	};
	let sum = function () {
		//...
		//调取开发者A编写的QUERY方法
		AModule.query();
	};
	return {
		query,
		init: function () {
			query();
			sum();
		}
	}
})();

AModule.init();
BModule.init();
复制代码

七、ES6中的新语法规范

* let / const
* class 建立类
* import / export :ES6 Module 模块的导入导出规范(JS中的模块化规范 AMD ->
 CMD -> CommonJS -> ES6 Module)
* Arrow Function 箭头函数
* 模板字符串
* 解构赋值
* '...'拓展、展开、剩余运算符
*  Promise / async / await
*  for of循环
*  Set / Map
* Array / Object ... 提供的新方法
复制代码

八、箭头函数与普通函数(function)的区别是什么?构造函数(function)可使用 new 生成实例,那么箭头函数能够吗?为何?

箭头函数

  • 语法上比普通函数更加简洁;
  • 没有ARGUMENTS,能够借助(...res)实现,而且接收值为数组;
  • 没有本身的THIS,定义时所在的THIS;

不可使用 new 命令:**

  • 箭头函数没有THIS,
  • 没有prototype属性,而NEW命令在执行的时候须要将构造函数的prototype赋值给新对象的__proto__
let Fn = () =>{
		this.x = 200;
	}
let f = new Fn;  // Uncaught TypeError: Fn is not a constructor
复制代码

八、怎么让一个 div 水平垂直居中?(很多于三种解决方案)

/* 已知宽高 */
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;  (减去盒子的一半)
    margin-left: -50px;
    width: 100px;
    height: 100px;
}
========================
/* 未知宽高 */
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
==========================
.box {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
===============================
[父级] {
    display: flex;
    justify-content: center;
    align-items: center;
}
复制代码

九、实现 (5).add(3).minus(2) ,使其输出结果为:6

// 每次方法执行完,都要返回NUMBER这个类的实例,这样才能够继续调取NUMBER类原型中的方法(链式写法);
~function () {
    // 保证传入值为数字
	function check(n) {
		n = Number(n);
		return isNaN(n) ? 0 : n;
	};

	function add(n) {
		n = check(n);
		return this + n;
	};
	
	function minus(n) {
		n = check(n);
		return this - n;
	}
	["add", "minus"].forEach(item => {
		Number.prototype[item] = eval(item);
	});
}();

let res = (5).add(3).minus(2);
console.log(res);  // => 6
复制代码

十、如何把一个字符串的大小写取反(大写变小写小写变大写),例如 ’AbC' 变成 'aBc' **

let str = 'JinTianTIanQiHenhao';
	str = str.replace(/[a-zA-Z]/g, content => {
			//content:每一次正则匹配到的结果;
			// 验证是否大写字母,统一转换成大写,再跟以前的字母对比,若是同样,说明以前也是大写;
			// 在ASCII 表中找到大写字母的取值范围进行判断(65-90);
		return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();
});
console.log(str)  // =>'jINtIANtiANqIhENHAO'
复制代码

十、实现一个字符串匹配算法,从字符串 S 中,查找是否存在字符串 T,若存在返回所在位置,不存在返回-1!(若是不能基于indexOf/includes等内置的方法,你会如何处理呢?

/* S: 查找S中T是否存在 pramas: [T] =>须要查找的字符串内容; return:存在返回其索引,不存在返回-1; */
// 循环原始字符串中每一项,让每一项从当前位置向后截取 T.length个字符,
// 而后和T进行比较,若是不同继续循环;若是同样返回当前索引便可;
// THIS:S =>原字符串;
// pramas: [T]=> 需查找的字符串;
// return: 匹配完整字符串开始的索引;
~function () {
   	function myIndexOf(T) {
        let lenT = T.length,
            lenS = S.length,
            res = -1;
        if (lenS < lenT) return null;
        for (let i = 0; i < lenS - lenT; i++) {
            if(this.substr(i, lenT) === T){
                res = i;
                break;  // 为了不出现多个符合,找最后一个,让其找到一个就结束;
            };               
        };
        return res;
    };
    String.prototype.myIndexOf = myIndexOf;
}();

let S = 'jingerzitiantianqihenhao',
    T = 'tian';
let res = S.myIndexOf(T);
console.log(res);

=========第二种=========
**使用正则匹配**

~function () {
    function myIndexOf(T) {
        let reg = new RegExp(T),
            res = reg.exec(this);
        return res === null ? -1 : res.index;
    }
    String.prototype.myIndexOf = myIndexOf;
}();

let S = 'jingerzitianqihenhao',
    T = 'tian';
let res = S.myIndexOf(T);
console.log(res); 
复制代码

十一、在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符合URL网址的格式

/* 在输入框中如何判断输入的是一个正确的网址,例如:用户输入一个字符串,验证是否符合URL网址的格式 */
//=>URL格式
//1.协议:// http/https/ftp
//2.域名
// www.sina.cn
// sina.cn
// kbs.sports.qq.com
// kbs.sports.qq.com.cn
//3.请求路径
// /
// /index.html
// /stu/index.html
// /stu/
//4.问号传参
// ?xxx=xxx&xxx=xxx
//5.哈希值
// #xxx

let str = "https://www.sina.com.cn";
let reg = /^(?:(http|https|ftp):\/\/)?((?:[\w-]+\.)+[a-z0-9]+)((?:\/[^/?#]*)+)?(\?[^#]+)?(#.+)?$/i;
console.log(reg.exec(str));
复制代码

十二、编写一条正则,用来验证此规则:一个6~16位的字符串,必须同时包含有大小写字母和数字

let reg = /(?!^[a-zA-Z]+$)(?!^[A-Z0-9]+$)(?!^[a-z0-9]+$)^[a-zA-Z0-9]{6,16}$/;
复制代码

1三、英文字母汉字组成的字符串,用正则给英文单词先后加空格

let str = "no做no死,你能你can!",
    reg = /\b[a-z]+\b/ig;
str = str.replace(reg, value => {
    return " " + value + " ";
}).trim();//=>String.prototype.trim/.trimLeft/.trimRight 去除字符串首尾空格
console.log(str);
复制代码

1四、改造下面代码,使之输出0-9

for (var i = 0; i < 10; i++) {
    setTimeout(() => {
        console.log(i);
    }, 1000);
}


//=>定时器是异步编程:每一轮循环设置定时器,无需等定时器触发执行,继续下一轮循环(定时器触发的时候,循环已经结束了)

=============第一种============
//=>LET存在块级做用域,每一次循环都会在当前块做用域中造成一个私有变量i存储0~9
//当定时器执行的时候,所使用的i就是所处块做用域中的i
for (let i = 0; i < 10; i++) {
	setTimeout(() => {
		console.log(i);
	}, 1000);
}     
    
    
============第二种=============
for (var i = 0; i < 10; i++) {
     ~function(i){
         setTimeout(() => {
              console.log(i);
         }, 1000);
     } (i)
 }

============第三种=============
for (var i = 0; i < 10; i++) {
   setTimeout((i => () => console.log(i))(i), 1000);
}

==============
=>能够基于bind的预先处理机制:在循环的时候就把每次执行函数须要输出的结果,预先传给函数便可
var fn = function (i) {
	console.log(i);
};
for (var i = 0; i < 10; i++) {
	setTimeout(fn.bind(null, i), 1000);
}
复制代码

1五、下面代码输出的结果是多少,为何?如何改造一下,就能让其输出 20 10?

var b = 10;
(function b() {
    b = 20;
    console.log(b);
})();
console.log(b);

---
 var b = 10;
(function b() {
	b = 20;
	console.log(b); //=>函数b
})();
console.log(b); //=>10 

 let fn = function AAA() {
	// "use strict";
	// AAA = 1000; //=>Uncaught TypeError: Assignment to constant variable.
	console.log(AAA); //=>当前函数
};
// AAA(); //=>Uncaught ReferenceError: AAA is not defined  
// 1.本应匿名的函数若是设置了函数名,在外面仍是没法调用,可是在函数里面是可使用的
// 2.并且相似于建立常量同样,这个名字存储的值不能再被修改(非严格模式下不错报,可是不会有任何的效果,严格模式下直接报错,咱们能够把AAA理解为是用 const 建立出来的)
fn(); */

=========================
 var b = 10;
(function b(b) {
	b = 20;
	console.log(b); //=>20 里面的b必定须要是私有的,不能是全局的(声明它或者改成形参)
})();
console.log(b); //=>10
复制代码

1六、下面代码a在什么值状况下会输出1

var a = ?;
if (a == 1 && a == 2 && a == 3) {
    console.log(1);
}

-----------
== 相对相等,若是左右两边数据类型不同,则先转换为相同的数据类型,而后在进行比较
 * 1. {}=={} 两个对象进行比较,比较的是堆内存的地址
 * 2. null==undefined 相等的  / null===undefined 不相等
 * 3. NaN==NaN 不相等  NaN和谁都不相等
 * 4. [12]=="12"  对象和字符串比较,是把对象toString()转换为字符串后再进行比较的
 * 5. 剩余全部状况在进行比较的时候,都是转换为数字(前提数据类型不同)
 *      对象转数字:先转换为字符串,而后再转换为数字
 *      字符串转数字:只要出现一个非数字字符,结果就是NaN
 *      布尔转数字:true->1  false->0
 *      null转数字0
 *      undefined转数字NaN

=======第一种========
// =>对象和数字比较:先把对象.toString()变为字符串,而后再转换为数字
a.toString(); //=>此时调取的就再也不是Object.prototype.toString了,调取的是本身私有的
var a = {
     n: 0,
     toString() {
         return ++this.n;
    }
}

=========第二种========
//=>shift:删除数组第一项,把删除的内容返回,原有数组改变
// 调取toString === a.shift;
let a = [1, 2, 3];
a.toString = a.shift;


=========第三种=========
// ES6中新增长的一些方法
// Object.defineProperty属性,执行window.a的时候,会先执行get这个函数,因此在get这个函数编写代码便可;
 Object.defineProperty(window, 'a', {
            get: function () {
                //=>this:window.a => undefined;
                this.value ? this.value++ : this.value = 1;
                return this.value;
            }
        });
复制代码

1七、下面代码的输出结果?为何?

let obj = {
    2: 3,
    3: 4,
    length: 2,
    push: Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);

// ---------------------------------
// => Array.prototype.push方法;
Array.prototype.push = function (...res) {
         res.forEach(item=>{
             this[this.length] = item;
         })
         return this.length;
 	 };

let arr = [1,2,3];
arr.push(1,'d',9,'hha',function(){});

console.log(arr.push(1,'d',9,'hha',function(){}))   // 8
console.log(arr);  // [1, 2, 3, 1, "d", 9, "hha", ƒ]

//=============
/obj.push(1);  obj[obj.length] = 1  => obj[2] = 1 
// 结果
obj = {
    2: 1,
    3: 4,
    length: 2,
    push: Array.prototype.push
}

/obj.push(2);  obj[3] = 2  => obj[2] = 2 
// 结果
obj = {
    2: 1,
    3: 2,
    length: 2,
    push: Array.prototype.push
}
复制代码

1八、完成以下需求

/* 某公司1到12月份的销售额存在一个对象里面 以下: { 1: 222, 2: 123, 5: 888 }, 请把数据处理为以下结构:[222, 123, null, null, 888, null, null, null, null, null, null, null] */


//=======第一种=======
let obj = {
    1: 222,
    2: 123,
    5: 888
};

let ary = new Array(12).fill(null).map((item,index) => {
            return obj[index+1] || item;
        });

console.log(ary)  // [222, 123, null, null, 888, null, null, null, null, null, null, null];


//========第二种========
let obj = {
    1: 222,
    2: 123,
    5: 888
};
obj.length = 13;

let ary = Array.from(obj).slice(1).map(item => {
    return typeof item === "undefined" ? null : item;
})
console.log(ary) // [222, 123, null, null, 888, null, null, null, null, null, null, null];

//=======第三种 =====
let obj = {
            1: 222,
            2: 123,
            5: 888
        };
// =>Object.keys(obj):获取obj中全部的属性名,以数组的方式返回

let arr = Object.keys(obj);
console.log(arr);   //["1", "2", "5"]

let ary = new Array(12).fill(null);
arr.forEach(item =>{
    ary[item - 1] = obj[item];
})
console.log(ary)  // [222, 123, null, null, 888, null, null, null, null, null, null, null]
复制代码

1九、给定两个数组, 写一个方法来计算它们的交集

et nums1 = [12, 23, 34, 23, 45, 34, 25, 46, 35];
let nums2 = [10, 35, 24, 23, 36, 47, 56];
//=> 输出结果 [22.23.25]

===========第一种==========
let arr = [];

nums1.forEach((item, index) => {
    let n = nums2.indexOf(item);
    if (n >= 0){
        arr.push(item);
        nums1.splice(index,1);
        nums1.splice(n,1);
    }
});
console.log(arr)  // [22.23.25]

==========第二种==========
let arr = [];

for (let i = 0; i < nums1.length; i++) {
    let item1 = nums1[i];
    for (let k = 0; k < nums2.length; k++) {
        let item2 = nums2[k];
        if (item1 === item2) {
            arr.push(item1);
            break;
        }
    }
}
console.log(arr);
复制代码

20、算法题「旋转数组」

/* 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数 输入: [1, 2, 3, 4, 5, 6, 7] 和 k = 3 输出: [5, 6, 7, 1, 2, 3, 4] 解释: 向右旋转 1 步: [7, 1, 2, 3, 4, 5, 6] 向右旋转 2 步: [6, 7, 1, 2, 3, 4, 5] 向右旋转 3 步: [5, 6, 7, 1, 2, 3, 4] 输入: [-1, -100, 3, 99] 和 k = 2 输出: [3, 99, -1, -100] 解释: 向右旋转 1 步: [99, -1, -100, 3] 向右旋转 2 步: [3, 99, -1, -100] */

========第一种=========
 let arr = [1, 2, 3, 4, 5, 6, 7];
function change(k) {
    if (k < 0 && k === this.length && k > this.length) return;
    if (k > this.length) return k = k % this.length;
    return this.slice(-k).concat(this.slice(0, this.length - k));
    // return [...this.splice(this.length-k),...this];
}
Array.prototype.change = change;

let ary = arr.change(3);
console.log(ary);   // [5, 6, 7, 1, 2, 3, 4]

=========第二种========
function change(k) {
            //=>参数处理
            if (k < 0 || k === 0 || k === this.length) return this;
            if (k > this.length) k = k % this.length;

            // for (let i = 0; i < k; i++) {
            // this.unshift(this.pop());
            // }
            new Array(k).fill('').forEach(() => this.unshift(this.pop()));
            return this;
        }
Array.prototype.change = change;
let ary = arr.change(3);
console.log(ary);   // [5, 6, 7, 1, 2, 3, 4]
复制代码
相关文章
相关标签/搜索