前端必须掌握的JavaScript基础知识
Posted hugo233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端必须掌握的JavaScript基础知识相关的知识,希望对你有一定的参考价值。
做为前端三剑客的javascript,可以说是重中之重了,是前端开发必不可缺的基础,因为有了JavaScript,才使静态的页面产生了一些动态的效果,你对JavaScript了解有多少?本文整理了个人学习中一些Javascript基础知识,以便查漏补缺。
1. 说一下你了解的主要浏览器及其内核
2. js中数据类型分为几种,都有哪些
-
简单数据类型:
number
、string
、Boolean
、null
、undefined
、symbol
-
复杂数据类型:
object
、array
、function
注意: 简单数据类型是没有属性和方法的且简单数据类型的值不可改变,保存复制的是值本身,储存在栈内存;引用数据保存与复制的是一个地址,改变其中一个另一个也会改变
3. 栈内存与堆内存的了解
- 栈内存 栈内存储存的都是一些比较简单的数据和堆内存的地址,举个例子
图中可以看出当改变了第一个num的值,num1的值不会因为num的值改变而改变,也再次印证了简单数据类型保存复制的是值本身
- 堆内存 堆内存储存的是一些比较复杂的数据,数据储存在堆内存,数据的地址保存在栈内存里面,举个例子
图中可以看出当改变了obj的name属性,obj1的name属性也跟着改变了,原因是 引用类型复制的是引用地址,obj和obj1指向的是堆内存中同一块空间,无论改变obj还是obj1 其实都是改变的同一个数据
3. typeof返回值有哪些
number
、 string
、Boolean
、 undefined
、 object
、 function
-
typeof typeof 返回 string
-
typeof null 、 typeof 对象 、 typeof 数组 都返回object
-
返回false的情况:
0
""
null
false
NaN
undefined
不成立的表达式
4. 如何检测一个对象是不是数组
- 第一种方法:
instanceof
运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。
分析过程:
图中可知 arr是Array构造出来的实例,arr.__proto__
属性指向了构造它的构造函数的原型对象Array.prototype
,由此得知 arr对象的原型链上有Array
构造函数的prototype属性。而arr.constructor
指向了构造它的构造函数,因为arr实例没有constructor
属性,就去原型链找,原型链上有constructor
,由此得知 arr.constructor === Array
注意: 但是此方法有漏洞,用此方法判断不一定准确,因为我们可以改变一个对象的this指向,这里就不做过多叙述了
- 第二种方法:
Object.prototype.toString
借用Object
原型上的方法来实现检测数组
分析过程:
toString
方法是Object原型上的方法,像function
,Array
作为Object的实例,重写了toString的方法。而我们通过原型链的知识可以知道,我们在调用toString方法时,并不能直接调用Object原型上的toString方法,调用的是重写后的方法。所以,我们想得到对象具体类型的话,应该使用call借调Object原型上的toString方法,这点MDN文档也有说明
- 第三种方法:
Array.isArray
此方法接收一个参数,用于确定传递的值是否是一个 Array
分析过程:
此方法为ES5新增的方法,可以直接判断参数是不是一个数组类型,MDN文档说明
5. 自增自减运算符和逻辑运算符
++
运算符: 写到后面叫做后自增,写到前面叫做先自增
let a = 10
let b = ++a + a++
console.log(a) // 12
console.log(b) // 22
//分析: ++a 是a先加1赋值给自己,此时a是11,再加上11,所以b等于11 + 11 = 22,最后a++,a变成了12
let a = 5
let b = a++ + ++a + a++
console.log(b) // 19
console.log(a) // 8
let a = 10
let b = a-- + ++a
console.log(b) // 20
console.log(a) // 10
-
--
运算符: 和自增运算符同,就不多说了 -
逻辑运算符
-
&&
: 假前真后,全真才为真 有一个假就是假 -
||
: 真前假后,全假才为假 有一个真就是真 -
!
: 取反 转换为布尔值
-
6. 冒泡排序
-
初级版本
- 让数组中每个值都两两进行比较一趟的结果,最大的数会在数组的最后面
let arr = [23, 46, 45, 39, 66, 82] for (let i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } console.log(arr) //分析:数组从arr[0]两两和后面数相比,一共比五次。所以让length - 1,让i最大取值到4就可以了。当i取值到4的时候 arr[4]和arr[5]相比,也就是arr.length - 2 和 arr.length - 1相比
- 让两两比较的结果多次运行,就会一次一次的把最大的数往后排,于是外面套一个for循环控制比多少趟
for (j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1; i++) { if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } }
-
高级版本
//第0趟 比较5次 多比了0次 //第1趟 比较4次 多比了1次 找到了1个最大的数 //第2趟 比较3次 多比了2次 找到了2个最大的数 //思路:遍历第一圈的时候,两两相比 一共比了5次,第二圈的时候由于已经找到了1个最大的数,此圈少比一次就可以了。但是for循环此时还是走了5圈,所以此时是多比了一次的 ,以此类推 let arr = [23, 46, 45, 39, 66, 82] for (j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1 - j; i++) { // 让length再减j if (arr[i] > arr[i + 1]) { let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } } }
-
终极版本 如果在排序过程中,发现数组已经排好序了,后面的次数就没必要排了
- 假设成立法
//判断数组中的成绩是否都及格了 let arr = [80,100,90,65,54] //第一种思路: for (let i = 0; i < arr.length; i++) { if (arr[i] >= 60) { console.log('都及格了') }else { console.log('不及格') } } //第二种思路:一旦找到小于60的 就代表并不是都及格了 for (let i = 0; i < arr.length; i++) { if (arr[i] < 60) { console.log('并未都及格') }
思路:排序过程中,假设数组是有顺序的那么就不用再次排序了。也就是说只要找到后一项比前一项大,那么假设就不成立
for (let i = 0; i < arr.length; i++) { if (arr[i] > arr[i + 1]) { console.log('假设失败') }
- 优化冒泡排序
let arr = [23, 46, 45, 39, 66, 82] for (j = 0; j < arr.length - 1; j++) { let flag = true for (let i = 0; i < arr.length - 1 - j; i++) { if (arr[i] > arr[i + 1]) { flag = false let temp = arr[i] arr[i] = arr[i + 1] arr[i + 1] = temp } else if (flag == true){ break } } }
7. 简述下浅拷贝与深拷贝
- 浅拷贝: 拷贝的是对象的一层属性,如果对象里面还有对象,则只会拷贝地址,修改其中一个会相互影响,适合拷贝简单数据类型
let obj = {
name: 'zs',
age: 18,
money: 1000
}
function Copy(obj) {
let newObj = {}
for (let k in obj) {
newObj[k] = obj[k]
}
return newObj
}
console.log(Copy(obj))
- 深拷贝: 拷贝对象的多层对象,如果对象里面还有对象,使用递归的方式去实现
let obj = {
name: 'zs',
age: 18,
money: 1000,
smoke: {
brand: 'suyan',
num: 20
}
}
function Copy(obj) {
let newObj = {}
for (let k in obj) {
newObj[k] = typeof obj[k] === 'object'? Copy(obj[k]) : obj[k]
}
return newObj
}
console.log(Copy(obj)) // 修改obj不会影响到newObj
8. 说一下你对原型和原型链的理解
函数都有prototype
属性,这个属性是一个对象,我们称之为原型对象;每一个对象都有__proto__
属性,该属性指向了原型对象,原型对象也是对象,也有__proto__
属性,这样一层一层形成了链式结构,我们称之为原型链
9. 闭包的理解
相互嵌套关系的两个函数,当内部函数引用外部函数的变量的时候就形成了闭包,闭包将会导致原有的作用域链不释放,造成内存泄露。有些地方说内部函数被保存到外部的时候形成闭包其实是不具体的,保存到外部只是为了方便调用内部的这个函数,而函数嵌套的原因则是因为需要局部变量,如果是全局变量就达不到闭包的目的了
-
闭包的优点: 形成私有空间,避免全局污染;持久化内存,保存数据
-
闭包的缺点: 持久化内存导致的内存泄露,解决办法 尽量避免函数的嵌套;执行完的变量赋值为null,让垃圾回收机制回收释放内存
经典案例:点击li获取下标
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
var lis = document.querySelectorAll('li')
for (var i = 0; i < lis.length; i++) {
(function (j) {
lis[j].onclick = function () {
console.log(j)
}
})(i)
}
10. call、apply、bind方法的区别
-
call和apply方法都可以调用函数,方法内的第一个参数可以修改this指向
-
call方法可以有多个参数,除了第一个参数标识this指向,其他参数作为函数的实参传递给函数; apply方法最多有两个参数,第一个参数标识this指向,第二个参数是一个数组或者伪数组,数组里面的每一项作为函数的实参传递给函数
-
bind方法不能自动调用函数,它会创建一个副本函数,并且绑定新函数的this指向bind返回的新函数
11. 伪数组有哪些
-
函数参数列表 arguments
-
DOM 对象列表 和 childNodes 子节点列表
-
jquery对象 比如$(“div”)
12. 伪数组和真数组有什么区别,伪数组如何转换为真数组呢
区别
-
伪数组其实是一个对象,真数组是Array
-
伪数组拥有length属性,但长度不可以改变,真数组长度是可以改变的
-
伪数组不具备真数组的方法,比如 push 、 slice等等
转换
- call借调数组方法
- ES6新语法 Array.from方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
- ES6新语法 扩展运算符
这里有个注意的点,使用自己定义的伪数组的时候,扩展运算符无法转换成真数组,百度了下才知道自己定义的伪数组由于缺少遍历器Iterator会报错
13. 了解过数组的降维(扁平化)吗
-
借调数组原型上的concat方法
let arr = [1,2,3,[4,5]] Array.prototype.concat.apply([], arr)
-
使用数组的concat方法和扩展运算符
let arr = [1,2,3,[4,5]] [].concat(...arr)
注意: 以上两种方法只能实现一层嵌套,如果是多层的嵌套就用下面两个方法
-
利用Array.some方法判断数组中是否还存在数组,如果存在用展开运算符配合concat连接数组
let arr = [1,2,3,[4,[5,6]]] while (arr.some(item => Array.isArray(item))) { arr = [].concat(...arr); } console.log(arr);
-
ES6中的flat函数实现数组的扁平化
let arr = [1,2,3,[4,[5,6]]] arr.flat( Infinity ) //flat方法的infinity属性,可以实现多层数组的降维
14. var
const
let
有哪些不同
-
var声明的变量存在变量提升,let const无
-
var可以重复声明同名变量, let const 不可以,会报错 has already been declared
-
let const 声明变量有块级作用域,var没有
-
const定义的变量是常量不能修改,但是如果是对象或者数组可以修改属性,增加属性
15. this指向问题
-
函数调用模式, this指向window
-
构造函数调用模式, this指向新创建的实例对象
-
方法调用模式, this指向调用方法的对象
-
上下文调用模式, call和apply方法中, this指向方法内的第一个参数;bind方法中, bind创建的新函数的this绑定为bind方法中新的函数
-
在事件处理函数中,this指向触发事件的当前元素
-
定时器中,this指向window
-
箭头函数中没有this指向问题,它的this和外层作用域的this保持一致
-
匿名函数中的this总是指向window
16. 你是如何理解面向对象的,它和面向过程有什么区别
-
面向对象是一种软件开发的思想,就是把程序看作一个对象,将属性和方法封装中,以提高代码的灵活性、复用性、可扩展性。面向对象有三大特性:
封装
继承
多态
。封装指的是把属性或者方法储存在对象中的能力,继承指的是由另一个类得来的属性和方法的能力,多态指的是编写能以多种方法运行的函数或方法的能力。面向对象开发优点是易维护
易扩展
降低工作量,缩短开发周期
,缺点是性能低 -
面向过程是一种以过程为中心的编程思想,就是把解决问题分为一个一个的步骤,先干什么后干什么,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程的优点就是性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素,缺点就是没有面向对象那样易维护、易扩展、易复用
17. 数组去重的方法
//第一种方法
const arr = [1,2,3,3,4,5,5,5,7]
const newArr = []
arr.forEach(item =>{
if(!newArr.includes(item)) {
newArr.push(item)
}
})
console.log(newArr)
//第二种方法 es6新增一个set方法 set有一个特征,内部的值不允许重复
const arr = [1,2,3,3,4,5,5,5,7]
const set = new Set(arr)
const newArr = [...set] // ... 展开运算符 可以展开数组或者对象
最后
为了让大家快速精通JavaScript,在这里免费分享给大家一份Javascript学习指南。
Javascript学习指南文档涵盖了javascript 语言核心、词法结构 、类型、值和变量 、表达式和运算符 、语句、对象 、数组 、函数 、类和模块 、 正则表达式的模式匹配、 javascript的子集和扩展 、服务器端javascript /客户端javascript 、web浏览器中的javascript 、window对象 、脚本化文档、脚本化css 、事件处理等22章知识点。内容丰富又详细,拿下互联网一线公司offfer的小伙伴都在看。
每个知识点都有左侧导航书签页,看的时候十分方便,由于内容较多,下面列举的部分内容和图片。
对象
- 创建对象
- 属性的查询和设置
- 删除属性
- 检测属性
- 枚举属性
- 属性getter和setter
- 属性的特性
数组
- 创建数组
- 数组元素的读和写
- 稀疏数组
- 数组长度
- 数组元素的添加和删除
- 数组遍历
- 多维数组
函数
- 函数定义
- 函数调用
- 函数的实参和形参
- 作为值的函数
- 作为命名空间的函数
- 闭包
- 函数属性、方法和构造函数
类和模块
- 类和原型
- 类和构造函数
- javascript中java式的类继承
- 类的扩充
- 类和类型
- javascript中的面向对象技术
- 子类
正则表达式的模式匹配
- 正则表达式的定义
- 用于模式匹配的string方法
- regexp对象
javascript的子集和扩展
- javascript的子集
- 常量和局部变量
- 解构赋值
- 迭代
- 函数简写
- 多catch 从句
- e4x: ecmascript for xml
web浏览器中的javascript
- 客户端javascript
- 在html里嵌入javascript
- javascript程序的执行
- 兼容性和互用性
- 可访问性
- 安全性
- 客户端框架
window对象
- 计时器
- 浏览器定位和导航
- 浏览历史
- 浏览器和屏幕信息
- 对话框
- 错误处理
- 作为window对象属性的文档元素
如果你有其他语言的编程经历,这份文档会有助你了解JavaScript是一门高端的、动态的、弱类型的编程语言,非常适合面向对象和函数式的编程风格。
我在这里将这份完整版的JS学习指南电子版文档提供出来,感兴趣的朋友都可以找我拿一份学习!(纯免费的一个分享,希望能给大家带来实质性的帮助)
快速入手通道:【点击这领取Javascript学习指南电子版】
你的支持,我的动力;祝各位前程似锦,offer不断!!!
以上是关于前端必须掌握的JavaScript基础知识的主要内容,如果未能解决你的问题,请参考以下文章
为什么学习web前端,必须掌握JavaScript这门编程语言