1.延迟加载JS
在script标签上添加async或者defer
<script defer type="text/javascript" src="script.js"></script>
defer:等html全都解析完成,顺次执行js脚本
async:js谁先加载完谁先运行
2.JS数据类型有哪些?
基本数据类型:String,Number,Boolean,undefined,null,Symbol,BigInt
引用数据类:Object
typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
因此采用typeof判断对象数据类型是不合适的,采用instanceof会更好,instanceof的原理是基于原型
链的查询,只要处于原型链中,判断永远为true
var str1 = 'hello world'
str1 instanceof String // false
字符串与别的相加都是字符串相连
undefined +1 --NAN 数值类型,但不是具体数字
3.null与undefined的区别
现有null,但是null转化为0,不容易发现错误。所以设计undefined
null 转为数值是 0 ; undefined 转为数值是 NAN(not a number)
null 通过 typeof 判断类型的时候结果的输出是 object ; 而 undefined 的类型是 undefined
4.==与===不同
null == undefined => true
string == number =>(隐式转换:string->number) true
boolean == number =>(boolean ->number) true
object == string|| number => (object 转换为基本类型)
隐式转换利用valueOf不会被体现出来
5.JS的微任务和宏任务
JS是单线程的语言,同一时间只能做一件事
执行流程:同步 =》事件循环【微任务、宏任务】
进入事件循环:请求、定时器、事件
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000 * i)
}
微任务:promise.then是微任务,promise是同步
宏任务:setTimeout
宏任务执行前先执行所有微任务
6.JS作用域ß
1)除了函数外,js没有块级作用域
2)作用域内可以访问外部变量,但是外部不能访问内部,如果内部有优先就近,没有向外查找
3)声明变量是用var还是没有写(window.)
4) js有变量提升的机制(变量悬挂)var声明不赋值,不报错,提前打印值为undefined
5) 优先级:声明变量 > 普通函数 > 参数 >变量提升
先查找本层有没有变量(包括变量提升)
js除了函数没有块级作用域,
普通声明函数是不看写函数顺序的
function c() {
var b = 1;
function a() {
console.log(b);
var b = 2;
console.log(b);
}
a();
console.log(b);
}
c() // undefined 2 1
// 《《《《《《《《《《
var name = "world";
(function () {
if (typeof name === 'undefined') {
var name = 'JACK';
console.log('GOODBYE' + name)
} else {
console.log('Hello ' + name)
}
})()
// GOODBYEJACK
// 《《《《《《《《《《
var bar = 1;
function test() {
console.log(bar);
var bar = 2;
console.log(bar)
}
test() // undefined 2;
7.JS对象
console.log([1, 2, 3] === [1, 2, 3]); //false
1.对象是通过new操作符构建出来,所以对象之间不相等(除了引用外)
2.对象注意:引用类型
3.对象的key都是字符串类型
4.对象查找属性
先在对象本身找 ==》构造函数找 ==》对象原型中找 ==》构造函数原型中找 ==》对象上一层原型上找
var obj1 = {
a: 'hello'
}
var obj2 = obj1
obj2.a = 'world'
console.log(obj1) // {a:world}
(function () {
console.log(a) // undefined
var a = 1;
})()
// 《《《《《《《《《《
var a = {};
var b = {
key: 'a'
}
var c = {
key: 'c'
}
a[b] = '123'; // a = {'[object,object]':'123'};
a[c] = '456'; // a = {'[object,object]':'456'};
console.log(a[b]); // '456'
1.每一个函数自带一个原型
注意:对象拥有__proto__
2.new Fun 该构造函数的原型指向于对象(new Fun)的原型
function Fun() {
this.a = '这是Fun函数中添加的'
}
Fun.prototype.a = '这是Fun函数原型添加的'
let obj = new Fun();
obj.a = '对象本身';
obj.__proto__.a = '这是对象原型添加的'
8.JS作用域 + this指向 + 原型
function Foo() {
getName = function () {
alert(1);
}
return this;
}
Foo.getName = function () {
alert(2);
}
Foo.prototype.getName = function () {
alert(3);
}
var getName = function () {
alert(4);
}
function getName() {
alert(5);
}
Foo.getName(); //2
getName(); //4
Foo().getName();//1
getName(); //1
new Foo().getName();//3
new Foo().getName;//f(){ alert(3); }
// 《《《《《《《《《《
// this指到离他最近的一个对象 ,全局是window
var o = {
a: 10,
b: {
fn: function () {
console.log(this.a);// undefined
console.log(this); // fn(){}
}
}
}
o.b.fn();
// 《《《《《《《《《《
window.name = 'Byte';
function A() {
this.name = 123;
}
A.prototype.getA = function () {
console.log(this);
return this.name + 1;
}
let a = new A;
let funcA = a.getA; // this.name= 'Byte'
// let funcA = a.getA();// this.name= '123'
funcA();
// 《《《《《《《《《《
var length = 10;
function fn() {
return this.length + 1;
}
var obj = {
length: 5,
test1: function () {
return fn();
}
}
obj.test2 = fn;
console.log(obj.test1()); // 11
console.log(fn() === obj.test2());// false this变了
console.log(obj.test1() == obj.test2()); // false
9.JS变量是不是数组
var arr = [1, 2];
// console.log(typeof(arr)); // 不可以 object
console.log(Array.isArray(arr));
console.log(arr instanceof Array);
console.log(Object.prototype.toString.call(arr).indexOf('Array') > -1)
console.log(Array.prototype.isPrototypeOf(arr));
console.log(arr.constructor.toString().indexOf('Array') > -1)
10.slice是干什么的,splice是否改变原数组
slice截取,找到坐标,之后的值,不改变原数组
var arr1 = ['a', 'v', 'd'];
var arr2 = arr1.slice(-1);
console.log(arr2)
splice 插入、删除、替换,改变原数组
arr1.splice(1,2) 删除1个,从2开始,改变原数组
11.JS去重
var arr3 = [1, 2, 3, 1, 4, 5];
console.log(new Set(arr3));
console.log(Array.from(new Set(arr3)));
console.log([...new Set(arr3)]);
function unique(arr) {
return [...new Set(arr)]
}
function unique2(arr) {
var brr = [];
arr.forEach(element => {
if (brr.indexOf(element) == -1) {
brr.push(element);
}
});
return brr;
}
function unique3(arr) {
arr = arr.sort();
var brr = [[arr[0]]];
arr.forEach((el, index) => {
if (el !== arr[index - 1]) {
brr.push(el);
}
})
return brr;
}
12.找出多维数组最大值
// 大数组分为四个小数组,将每个小数组内最大的值串联出来,形成一个新的数组
function fnArr(arr) {
var newArr = [];
arr.forEach((item, index) => {
newArr.push(Math.max(...item))
})
return newArr;
}
13.给字符串新增方法实现功能
String.prototype.addText = function (str) {
return str + this;
}
console.log('sdfsfsdf'.addText('dsf'));
14.找出字符串出现最多次数的字符以及次数
var str = 'sdfsdfsasdfsgddd4tgrg';
var obj = {};
for (var i = 0; i < str.length; i++) {
var char = str.charAt(i);
if (obj[char]) {
obj[char]++;
} else {
obj[char] = 1;
}
}
console.log(obj);
var max = 0;
for (var key in obj) {
if (max < obj[key]) {
max = obj[key];
}
}
for (var key in obj) {
if (obj[key] == max) {
console.log(key + ':' + max)
}
}
15.new操作符具体做了什么
function create(fn, ...args) {
// 1.创建一个空的对象
var obj = {};
// 2.将空对象的原型,指向于构造函数的原型
Object.setPrototypeOf(obj, fn.prototype);
// 3.将空对象作为构造函数的上下文(改变this指向)
var result = fn.apply(obj, args);
// 4.对构造函数有返回值的处理判断
return result instanceof Object ? result : obj;
}
function hh() {
console.log(this);
};
console.log(new hh());
16.闭包
a.闭包是什么
闭包是一个函数加上创建函数的作用域的连接,闭包“关闭”了函数的自由变量
b.闭包可以解决什么问题
内部函数可访问到外部变量的局部变量
闭包可以解决问题
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
(function (i) {
lis[i].onclick = function () {
alert(i)
}
lis[i] = null;
})(i)
}
c.闭包的缺点
变量会驻留在内存中,早晨内存损耗问题
把闭包函数设为null
内存泄露是IE浏览器存在问题
17.原型链
a.原型可以解决什么问题
共享属性、共享方法
b.谁有原型
function.prototype === obj.__proto__
function Fun() {
this.run = '1';
}
Fun.prototype.run = '2';
var obj = new Fun();
obj.run = '3';
obj.__proto__ = '4';
Object.prototype.run = '5';
console.log(obj.run)
c.对象查找属性或者方法的顺序
现在对象本身查找 -》构造函数查找 -》原型查找 -》构造函数的原型查找 -》当前原型的原型查找
d.原型链:把原型串联起来,最顶端null
17.JS继承方式
// 方式一:ES6
class Parent1 {
constructor() {
this.age = 18;
}
}
class Child1 extends Parent1 {
constructor() {
super();
this.name = '张三'
}
}
let o1 = new Child1();
console.log(o1, o1.name, o1.age)
// 方式二:原型链继承
function Parent2() {
this.age = 18;
}
function Child2() {
this.name = '张三'
}
Child2.prototype = new Parent2();
let o2 = new Child2();
console.log(o2, o2.name, o2.age)
// 方式三:借用构造函数
function Parent3() {
this.age = 18;
}
function Child3() {
this.name = '张三'
Parent3.call(this);
}
let o3 = new Child3;
console.log(o3, o3.name, o3.age)
// 方式四:组合式继承
function Parent4() {
this.age = 100;
}
function Child4() {
Parent4.call(this);
this.name = '张三'
}
Child4.prototype = new Parent4();
let o4 = new Child4();
console.log(o4, o4.name, o4.age)
18.call apply bind的区别
共同点:都可以改变this指向
var str = '你好';
var obj = {
str:'这是obj对象内部的str'
}
function fun(name,age) {
console.log(this , this.str);
}
// fun.call( obj ,'123sdddd',18); //call会立即执行
// fun.apply( obj,['123sdddd',18] )//apply会立即执行
// fun.bind( obj,'123sdddd',18 )()
fun.bind( obj ) // bind 不会立即执行 fun.bind( obj )()
fun();
区别:
1.call,apply可以立即执行,bind不会立即执行,因为bind的返回的是一个函数需要加入()执行
2.参数不同:apply 第二个参数是数组,call和bind有多个参数需要挨个写
场景:
// 1.用apply的情况
var arr1 = [1,2,3,4,5,7,78,223]
console.log(Math.max.apply(null,arr1));
// 2.用bind的情况
btn.onclick = function () {
console.log(this.id)
}.bind(hls)
19.sort原理
sort()方法用于对数组元素的排序并返回数组,默认排序顺序是根据字符串unicode
array.sort(sortby);参数sortby可选,规定顺序排序,必须是函数;
如果调用该方法时没有使用参数,将按照字母顺序对数组中元素进行排序,说的更精确点,是按照字符编码进行排序,要实现这一点,
console.log(arr1.sort());
console.log(arr1.sort(function (a,b) {
return a - b;
}));
// 有对象的数组
function funSort(age) {
return function(a,b){
var val1 = a[age];
var val2 = b[age];
return val1 - val2;
}
}
var arr5 = arr4.sort(funSort('age'));
console.log(arr5)
// v8引擎排序,之前数量小于10用插入排序,数量大于10,快速排序,现在是冒泡
20.深拷贝和浅拷贝
共同点:复制
浅拷贝:只复制引用,未复制真正的值(相互影响)
var objC1 = {a:1,b:2}
var objC2 = Object.assign(objC1);
console.log(objC1,objC2)
深拷贝:是复制真正的值(不同引用)
// 方法一:JSON.parse
var objC3 = {
a:1,
b:2
}
var objC4 = JSON.parse(JSON.stringify(obj3));
console.log(objC3,objC4);
// 方法二:递归的形式
function copyObj(obj) {
if(Array.isArray(obj)){
var newObj = [];
}else{
var newObj = {}
}
for(var key in obj){
if(typeof obj[key]== 'object'){
newObj[key] = copyObj(obj[key])
}else{
newObj[key] = obj[key]
}
}
return newObj;
}
21.localStorage sessionStorage cookie的区别
a.cookie数据始终携带在同源的http请求中,即cookie在浏览器和服务器间来回传递,而sessionStorage和Localstorage不会自动把数据发送给服务器,只在本地保存。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。
b.存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所有cookie只适合保存很小的数据。如会话标识。sessionStorage和Localstorage虽然也有大小储存的限制,但比cookie大很多。可以达到5M或更大。
c.数据有效期不同,sessionStorage,仅在当前浏览器窗口关闭之前有效,Localstorage始终有效,窗口或者浏览器关闭也一直保存,除非手动删除,cookie只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭。
d.作用域不同,sessionStorage不能在不同的浏览器中共享,即使是同一个页面,locastorage在所有的同源窗口中都是共享的,cookie也是在所有同源窗口中共享的。
e.web Storage支持事件通知机制,可以将数据更新的通知发送给监听者。
f.web storage 的api接口使用更方便。
22.var let const 的区别
a.var具有变量提升的机制,let和const没有变量提升的机制
b.var可以多次声明同一个变量,let和const不行
c.var let声明变量,const声明常量
var let可以改变值的大小 const不可以改,但是内层const没有声明可以更改
23.作用域
注意一:let const没有变量提升性
注意二:
function demo() {
let n = 2;
if( true ){
let n =1;
}
console.log(n);//2
}
demo();
24.合并下列对象
const a = {a:1,b:4};
const b = {b:2,c:3};
// 方式一:
let objS1 = Object.assign(a,b);
console.log( objS1 );
// 方式二:s
let objS2 = { ...a,...b }
console.log( objS2 );
// 方式三:
function extend(target,source) {
for(var obj in source){
target[obj] = source[obj];
}
return target;
}
console.log( extend(a,b));
25.箭头函数和普通函数的区别
a.指向的问题
箭头函数中this只在箭头函数定义时就决定的,而且不可修改(call\apply\bind)
箭头函数的this指向定义的时候、外层第一个普通函数this
b.箭头函数不能new(不能当做构造函数)
c.箭头函数没有prototype
e.箭头函数没有arguments
let obj = {
a:function () {
console.log(this); //函数自身
},
b: () => {
console.log(this);// window
}
}
26.promise 有几种状态
a.promise:pending(进行中) fulfilled(已成功) reject(已失败)
b.generator函数
* getData(){
yield http.$axios({url:'/home'});
yield http.$axios({url:'/api'});
}
let t = this.getData();
// console.log(t.next().value);
t.next().value.then(res =>{
console.log(res);
}) // home
t.next().value.then(res =>{
console.log(res);
}) // api
// async await
async created(){
let p = await http.$axios({url:'/home'});
}
27.find和filter 的区别
区别一:返回内容不一样
filter 返回是新数组
find 返回具体的内容
let arr = [123,12,23,44,3,53,43,45,6,4,5]
console.log(arr.filter(val=>{return val>10})) //[123, 12, 23, 44, 53, 43, 45]
console.log(arr.find(val=>{return val>10})) //123
区别二
filter 返回整个整体(每一个匹配到的都返回)
find 匹配到第一个即返回
28.some和every的区别
some 有一个匹配就返回true
every 全部匹配才会返回true
var arrA = [1,4,2,10,6];
var brr = arrA.some(val => {
return val >4;
}) // true
var crr = arrA.every(val=>{
return val>4;
}) // false