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) // undefinedvar 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);// undefinedconsole.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