JavaScript 常用概念及其介绍

JS的继承(含Es6)

ES5:ES5的继承主要是基于prototype来实现的

  • 原型链继承 即将b的原型改变为a
b.prototype = new a()
  • 构造函数继承 在b中改变其this指向为a
 function b(name,age) {
   			a.call(ths,name,age)
  }
  • 组合继承 组合继承则为上面两种的结合

ES6:用class定义类,用extends继承类

      例如:创建Aclass Aconstructor() {
   //构造器代码,new时自动执行
  }class B extends A {
  constructor() {
   super() //表示父类
  }
}
JS原生事件的绑定

js原生绑定事件主要有三种

  1. html事件处理程序

    表现为直接在html各类标签上直接添加事件,类似于css的行内式,但因为直接散落在标签中 也有着不易维护的缺点

  2. DOM0级事件处理程序

    表现为js获取dom然后直接给dom元素绑定一个事件

var btn=document.getElementById(‘id元素’)
btn.onclick=function() {
	// 逻辑
}
  1. DOM2级事件处理程序

    添加事件监听,支持给个元素绑定多个相同事件,支持冒泡和捕获事件机制

var btn=document.getElementById(‘id元素’)
   //绑定事件
btn.addEventListener(‘click’,绑定的事件处理函数名,false)
   //移除事件
btn.removeEventListener(‘click’,要移除的事件处理函数名,false)
JS原生常用dom操作方法

js原生dom操作方法有

  • 查找:
    • getElementByid,
    • getElementsByTagName,
    • querySelector,
    • querySelectorAll
  • 插入:
    • appendChild,insertBefore
  • 删除:
    • removeChild
  • 克隆:
    • cloneNode
  • 设置和获取属性:
    • setAttribute(“属性名”,”值”)
    • getAttibute(“属性名”)
JS面向对象

ECMAScript 有两种开发模式:

  1. 面向过程(每一步都要自己完成)
  2. 面向对象
    “面向对象的方法主要是把事物给对象化,包括其属性和行为。面向对象编程更贴近实际生活的思想。总体来说面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象,(万物皆对象)。”

面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript 没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。

ES5之前js本身是没有class类型的,但是每个函数都有一个prototype属性。prototype指向一个对象,当函数作为构造函数时,prototype则起到类似class的作用。

自从有了ES6后,把面向对象类的实现更像后端语言的实现了,通过class来定义类,通过extends来继承父类,其实ES6类的实现本质上是一个语法糖,不过对于开发简单了好多

JS数组常用方法

在开发中,数组使用频率很频繁,JS数组常用方法有

末尾添加 - push
删除最后一个 - pop
删除最前一个 - unshift
首部添加 - shift
添加或删除 - splice
拼接为字符串 - join
连接若干数组 - concat
循环 - forEach
过滤 - filter
映射 - map
排序 - sort
匹配单个 - some
匹配所有 - every

JS数组内置遍历方法及其区别
  • forEach 取代for循环遍历数组 返回值为undefined
let arr=[4,6,6,8,5,7,87]
arr.forEach((item,index,arr)=>{
  //遍历逻辑
})

其中:
item代码遍历的每一项,
index:代表遍历的每项的索引,
arr代表数组本身

  • filter 过滤遍历的方法,如果返回条件为true,则返回满足条件为true的新数组
 let arr=[4,16,6,8,45,7,87]
 let resArr=arr.filter((item,index,arr)=>{
  //例如返回数组每项值大于9的数组
  return item>9
})
  • map 主要对数组的复杂逻辑处理时用的多,特别是react中遍历数据,也经常用到,写法和forEach类似

  • some 用于只要数组中至少存在一个满足条件的结果,返回值就为true,否则返回fasel, 写法和forEach类似

  • every 用于数组中每一项都得满足条件时,才返回true,否则返回false, 写法和forEach类似

JS作用域

JS作用域也就是JS识别变量的范围

JS作用域主要包括全局作用域、局部作用域和ES6的块级作用域
  • 全局作用域:也就是定义在window下的变量范围,在任何地方都 可以访问,
  • 局部作用域:是只在函数内部定义的变量范围
  • 块级作用域:简单来说用let和const在任意的代码块中定义的变量都认为是块级作用域中的变量,在每一个{}中都可以认为是一个块级作用域

作用域链就是由最内部的作用域往最外部,查找变量的过程.形成的链条就是作用域链
JavaScript属于静态作用域,有时也称为词法作用域。

输入URL到页面加载完中间发生的事情

大致过程是这样的:

  1. 通过DNS服务器:url=>ip地址;

  2. 到达ip地址对应的服务器;

  3. 服务器接收用户的请求;

  4. 把处理后的结果返回给客户端;

  5. 客户端把结果渲染到浏览器即可,最后页面显示出来

JS的事件委托及其实现原理

JS事件代理就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的target属性实现

var ul = document.querySelector("ul");
// ul绑定点击事件
 ul.onclick = function(e){
 // e指event,事件对象
 var target = e.target || e.srcElement; 
 // target获取触发事件的目标(li)
   if(target.nodeName.toLowerCase() == 'li'){
   // 目标(li)节点名转小写字母,不转的话是大写字母alert(target.innerHTML)
   }
 }

jq方式实现相对而言简单 $(“ul”).on(“click”,“li”,function(){//事件逻辑}) 其中第二个参数指的是触发事件的具体目标,特别是给动态添加的元素绑定事件,这个特别起作用

call,apply,bind区别

主要作用都是改变this指向的
call和apply 的区别主要表现为传递参数的不同
··· call 后面传递的参数是以逗号的范式分隔的,
··· apply 传递的参数是以数组形式
bind 返回的是是个函数形式,如果要执行 则后面要再加一个小括号
bind 只能以逗号分隔形式,不能是数组形式
例如:bind(obj,参数1,参数2,)

ES6模块与CommonJS模块的区别

CommonJS

  1. 对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
  2. 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
  3. 当使用require命令加载某个模块时,就会运行整个模块的代码。
  4. 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
  5. 循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出

ES6模块

  1. ES6模块中的值属于【动态只读引用】。
  2. 对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
  3. 对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
  4. 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。
null与undefined的区别

null表示为空,代表此变量是一个空的 可以给其赋值
undefined表示『不存在』代表此变量不存在 应先声明再输出

箭头函数的this指向

箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于自己的this,它的所谓的this是捕获其所在上下文的 this 值(即父级的this),作为自己的 this 值
且由于没有属于自己的this,而箭头函数是不会被new调用的,不可作为构造函数使用

async/await

async 用于声明一个异步函数

async function someName(){...}

··· 自动将常规函数转换成Promise,返回值也是一个Promise对象
··· 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
··· 异步函数内部可以使用await

await 暂停异步的功能执行

var result = await someAsyncCall()

··· 放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果
···只能与Promise一起使用,不适用与回调
···只能在async函数内部使用

😉

async/await相比于Promise的优势
  1. 可读性更好 Promise虽然摆脱了回调地狱 但是then的链式调用也会带来额外的阅读负担
  2. Promise传递中间值非常麻烦,而async/await几乎是同步的写法 简单明了
  3. async/await可以用成熟的try/catch,Promise中的错误捕获非常冗余
  4. 相比于 Promise 更易于调试。

因为没有代码块,所以不能在一个返回的箭头函数中设置断点。如果你在一个 .then 代码块中使用调试器的步进(step-over)功能,调试器并不会进入后续的 .then 代码块,因为调试器只能跟踪同步代码的每一步。
在这里插入图片描述

现在,如果使用 async/await,你就不必再使用箭头函数。你可以对 await 语句执行步进操作,就好像他们都是普通的同步语句一样。
在这里插入图片描述

JavaScript的异步编写方式,从 回调函数 到 Promise、Generator 再到 Async/Await。表面上只是写法的变化,但本质上则是语言层的一次次抽象。让我们可以用更简单的方式实现同样的功能,而不需要去考虑代码是如何执行的。

换句话说就是:异步编程的最高境界,就是根本不用关心它是不是异步。

JavaScript的基本类型和复杂类型

基本数据类型储存在栈中,复杂数据类型会存储在堆中

但是基本数据类型一旦被闭包引用则成为常住内存,会储存在内存堆中。

JavaScript的同步与异步的区别

同步(阻塞进程)
代码从上往下依次执行,执行完当前代码,才能执行下面的代码。
异步(非阻塞)
代码从上往下依次执行,没执行完当前代码,也能执行下面的代码。

JavaScript垃圾回收原理

垃圾回收:js代码想要运行,需要操作系统或者运行时提供内存空间,来存储变量及它的值。在某些变量(例如局部变量)在不参与运行时,就需要系统回收被占用的内存空间,称为垃圾回收

内存泄漏:某些情况下,不再用到的变量所占内存没有及时释放,导致程序运行中,内存越占越大,极端情况下可导致系统崩溃、服务器宕机。

JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存

由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

---------《JavaScript权威指南(第四版)》

在JavaScript中如果一个对象不再被引用 那么这个对象就会被GC回收
且如果两个对象互相引用,而不再被第3者所引用,那么这两个对象也会被回收。

深拷贝和浅拷贝的区别

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。浅拷贝只复制对象的第一层属性
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。对对象的属性进行递归复制

浅拷贝:

  1. ES6中的…扩展运算符可以实现
  2. var a = b;赋值也可以实现
  3. Object.assign()实现

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
注意:当object只有一层的时候,是深拷贝

深拷贝:

  1. 对象只有一层的情况下 可以使用上方的Object.assign()实现
  2. 通过 JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象 也可以实现深拷贝
  3. 使用Object.create()方法
    直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
浏览器渲染页面的过程
  1. 解析html文件 创建DOM树(自上而下)
  2. 解析css
  3. 将css和dom合并 构建渲染树
  4. 布局和绘制

reflow(回流)

说到页面为什么会慢?那是因为浏览器要花时间、花精力去渲染,尤其是当它发现某个部分发生了点变化影响了布局,需要倒回去重新渲染, 该过程称为reflow(回流)。
reflow几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会reflow哪一部分的代码,它们都彼此相互影响着。

repaint(重绘)

如果只是改变某个元素的背景色、文 字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器repaint(重绘)。repaint的速度明显快于reflow(在IE下需要换一下说法,reflow要比repaint更缓慢)。

JSON和JSONP的区别

json是一种数据格式,
jsonP则是跨域的一种解决方法

jsonp的全名叫做json with padding,就是把json对象用符合js语法的形式包裹起来以使其他的网站可以请求到,也就是将json封装成js文件传过去。

阻止事件冒泡和取消默认事件

冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。
而与之相对的是捕获型事件 他的理念正好与冒泡事件相反 事件按照从外层的事件目标到具体的事件目标

使用event.stopPropagation()起到阻止捕获和冒泡阶段中当前事件的进一步传播。
使用event.preventDefault()return false 可以取消默认事件。

但对于IE来说

阻止事件冒泡
e.cancelBubble = true
取消默认事件
window.event.returnValue = false;

javaScript中的内存泄漏

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用
数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象 的内存即可回收。

  1. 闭包
  2. 控制台日志
  3. 循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
  4. setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
JavaScript 中的强制转型

强制转型 顾名思义 就是对一个变量的类型进行强制转换
由于写法的问题 分为两种 显式和隐式
显式

var a = "42";
var b = Number( a );
a; // "42"
b; // 42 -- 是一个数字!

隐式

var a = "42";
var b = a * 1; // "42" 隐式转型成 42 
a; // "42"
b; // 42 -- 是个数字!
JavaScript 中的提升操作

变量提升和函数提升

提升(hoisting)是 JavaScript 解释器将所有变量和函数声明移动到当前作用域顶部的操作

使用 var 声明的变量或函数 无论在作用域的任何地方 它的声明都会提升 并且可以在作用域的任何地方访问到它

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值