javascript知识简略

本文概述了JavaScript中的闭包概念,原型链的工作原理,原生事件绑定和DOM操作技巧,以及ES6新增的模块、作用域和异步处理。还介绍了数组遍历、作用域控制、事件代理、call/apply/bind的区别和优化编码策略。
摘要由CSDN通过智能技术生成

javascript知识简略

一、闭包

1、闭包:MDN的解释:闭包是函数和声明该函数的词法环境的组合。
说白了就是函数嵌套函数,内部函数能够访问外部函数的变量

	(function() { var a = 1; function add() { var b = 2 var sum = b + a console.log(sum); 
	// 3 }
	add() })()

2、作用

  • 闭包最大的作用就是隐藏变量,闭包的一大特性就是内部函数总是可以访问其所在的外部函数
    中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后
  • 基于此特性,JavaScript可以实现私有变量、特权变量、储存变量等
  • 我们就以私有变量举例,私有变量的实现方法很多,有靠约定的(变量名前加_),有靠Proxy
    代理的,也有靠Symbol这种新数据类型的。

3、优点

  • (1)、可以隔离作用域,不造成全局污染
  • (2)、长期驻扎在内存中
  • (3)、私有成员的存在

4、缺点

  • 由于闭包长期驻留内存,则长期这样会导致内存泄露
  • 如何解决内存泄露:将暴露全外部的闭包变量置为null
  • 内存的使用量大

5、适用场景:封装组件,for循环和定时器结合使用,for循环和dom事件结合.可以在性能优化的过程
中,节流防抖函数的使用,导航栏获取下标的使用

实例:

function outer(){ 
	var val = 0; 
	return function (){
	val += 1; document.write(val + "<br />"); 
	}; 
}
var outObj = outer(); 
outObj();//1,执行val += 1后,val还在
outObj();//2 
outObj = null;//val 被回收
var outObj1 = outer();
outObj1();//1
outObj1();//2

二、原型链

原型链是理解JS面向对象很重要的一点,这里主要涉及到两个点,一是_ proto ,二是prototype;

具体流程: 首先在p1对象实例上查找是否有有play方法,如果有则调用执行,如果没有则用p1.proto(proto是一
个指向的作用,指向上一层的原型)往创建p1的类的原型上查找,也就是说往Person.prototype上查找,
如果在Person.prototype找到play方法则执行,否则继续往上查找,则用Person.prototye.proto继续
往上查找,找到Object.prototype,如果Object.prototype有play方法则执行之,否则用
Object.prototype.proto继续再往上查找,但Object.prototpye.proto上一级是null,也就是原型链的顶
级,结束原型链的查找

三、js原生事件的绑定

JS原生绑定事件主要为三种:
一是html事件处理程序
二是DOM0级事件处理程序
三是DOM2级事件处理程序
其中:html事件现在早已不用了,就是在html各种标签上直接添加事件,类似于css的行内样
式,缺点是不好维护,因为散落在标签中,也就是耦合度太高

四、js原生dom操作

1、查找:
	getElementByid,
	getElementsByTagName,
	querySelector,
	querySelectorAll
2、插入:

appendChild,insertBefore

3、删除:

removeChild

4、克隆:

cloneNode

5、设置和获取属性:

setAttribute(“属性名”,”值”)
getAttibute(“属性名”)

五、es6新增特性

  1. 新增了块级作用域(let,const)
  2. 提供了定义类的语法糖(class)
  3. 新增了一种基本数据类型(Symbol)
  4. 新增了变量的解构赋值
  5. 函数参数允许设置默认值,引入了rest参数,新增了箭头函数
  6. 数组新增了一些API,如 isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等
    方法
  7. 对象和数组新增了扩展运算符
  8. ES6 新增了模块化(import/export)
  9. ES6 新增了 Set 和 Map 数据结构
  10. ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例
  11. ES6 新增了生成器(Generator)和遍历器(Iterator)

六、js数组内置遍历方法

JS数组内置遍历(遍历就是循环的意思)方法主要有:

  • forEach
    这个方法是为了取代for循环遍历数组的,返回值为undefined例如:
let arrInfo=[4,6,6,8,5,7,87] arrInfo.forEach((item,index,arr)=>{ //遍历逻辑 })

其中:

  • item代码遍历的每一项,
  • index:代表遍历的每项的索引,
  • arr代表数组本身
  • filter
    是一个过滤遍历的方法,如果返回条件为true,则返回满足条件为true的新数组
let arrInfo=[4,16,6,8,45,7,87] 
let resultArr=arrInfo.filter((item,index,arr)=>{ 
//例如返回数组每项值大于9的数组 return item>9 })
  • map
    这个map方法主要对数组的复杂逻辑处理时用的多,特别是react中遍历数据,也经常用到,
    写法和forEach类似
  • some
    这个some方法用于只要数组中至少存在一个满足条件的结果,返回值就为true,否则返回
    fasel, 写法和forEach类似
  • every
    这个every方法用于数组中每一项都得满足条件时,才返回true,否则返回false, 写法和
    forEach类似

七、js作用域

  • JS作用域也就是JS识别变量的范围,作用域链也就是JS查找变量的顺序
  • 先说作用域,JS作用域主要包括全局作用域、局部作用域和ES6的块级作用域
    • 全局作用域:也就是定义在window下的变量范围,在任何地方都可以访问,
    • 局部作用域:是只在函数内部定义的变量范围
    • 块级作用域:简单来说用let和const在任意的代码块中定义的变量都认为是块级作用域中的变
      量,例如在for循环中用let定义的变量,在if语句中用let定义的变量等等

注:

  1. 尽量不要使用全局变量,因为容易导致全局的污染,命名冲突,对bug查找不利。
  2. 而所谓的作用域链就是由最内部的作用域往最外部,查找变量的过程.形成的链条就是作用域链

八、事件代理及其原理

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

var ul = document.querySelector("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的区别

call,apply,bind主要作用都是改变this指向的,但使用上略有区别,说一下区别

  • call和apply的主要区别是在传递参数上不同,call后面传递的参数是以逗号的形式分开的,apply
    传递的参数是数组形式 [Apply是以A开头的,所以应该是跟Array(数组)形式的参数]
  • bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号 例如:bind(obj,参数1,参数2)(),bind只能以逗号分隔形式,不能是数组形式

十、es6模板与commonjs模块有何区别

  • ES6 Module和CommonJS模块的区别:- CommonJS是对模块的浅拷贝,ES6 Module是对模块的引用,即ES6 Module只存只读,不能改变其值,具体点就是指针指向不能变,类似const
  • import的接口是 read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但
    可以改变变量内部指针指向,可以对commonJS对重新赋值(改变指针指向),但是对ES6 Module
    赋值会编译报错。

ES6 Module和CommonJS模块的共同点:

  • CommonJS和ES6 Module都可以对引入的对象进行赋值,即对对象内部属性的值进行改变。

十一、await/async是什么

async 函数,就是 Generator 函数的语法糖,它建立在Promises上,并且与所有现有的基于Promise的
API兼容。

  1. Async—声明一个异步函数(async function someName(){…})
    • 自动将常规函数转换成Promise,返回值也是一个Promise对象
    • 只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数
    • 异步函数内部可以使用await
  2. Await—暂停异步的功能执行(var result = await someAsyncCall()😉
    • 放置在Promise调用之前,await强制其他代码等待,直到Promise完成并返回结果
    • 只能与Promise一起使用,不适用与回调
    • 只能在async函数内部使用

十二、async/await相比于promise的优势

  • 代码读起来更加同步,Promise虽然摆脱了回调地狱,但是then的链式调用也会带来额外的阅读负
  • Promise传递中间值非常麻烦,而async/await几乎是同步的写法,非常优雅
  • 错误处理友好,async/await可以用成熟的try/catch,Promise的错误捕获非常冗余
  • 调试友好,Promise的调试很差,由于没有代码块,你不能在一个返回表达式的箭头函数中设置断
    点,如果你在一个.then代码块中使用调试器的步进(step-over)功能,调试器并不会进入后续
    的.then代码块,因为调试器只能跟踪同步代码的『每一步』。

十三、同步与异步的区别

  • 同步:
    • 浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出
      现,用户看到新内容,进行下一步操作
    • 代码从上往下依次执行,执行完当前代码,才能执行下面的代码。(阻塞)
  • 异步:
    • 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内
      容也会出现,用户看到新内容
    • 代码从上往下依次执行,没执行完当前代码,也能执行下面的代码。(非阻塞)

十四、深拷贝与浅拷贝

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

浅拷贝:

  • 使用Object.assign({},obj)第一个参数是一个空对象,第二个参数是你要复制的对象;通过这
    个方法我们知道浅拷贝不能修改基础的数据类型,可以修改引用的数据类型;
  • ES6中的…扩展运算符来进行浅拷贝的实现;
  • Object.assign()实现
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目 标对象。
但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本 身。
var obj = { a: {a: "hello", b: 21} };
var initalObj = Object.assign({}, obj);
initalObj.a.a = "changed";
console.log(obj.a.a); // "changed"
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1); 
obj2.b = 100; console.log(obj1); 
// { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); 
// { a: 10, b: 100, c: 30 }

深拷贝:

  • 对象只有一层的话可以使用上面的:Object.assign()函数
  • 转成 JSON 再转回来
var obj1 = { body: { a: 10 } };
 var obj2 = JSON.parse(JSON.stringify(obj1)); 
 obj2.body.a = 20; 
 console.log(obj1); 
 // { body: { a: 10 } } <-- 沒被改到 console.log(obj2); 
 // { body: { a: 20 } } console.log(obj1 === obj2);
 // false 
console.log(obj1.body === obj2.body); 
// false

用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。

  • 使用Object.create()方法
    直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
function deepClone(initalObj, finalObj) {
	 var obj = finalObj || {};
	  for (var i in initalObj) {
	   var prop = initalObj[i]; 
	   // 避免相互引用对象导致死循环,如 initalObj.a = initalObj的情况
	    if(prop === obj) {
	     continue; 
	    }
		if (typeof prop === 'object') {
		 obj[i] = (prop.constructor === Array) ? [] : Object.create(prop); 
		} else {
		 obj[i] = prop; 
		 	} 
		 }
	 return obj; 
}

十五、json与jsonp的区别

  • json返回的是一串json格式数据;而jsonp返回的是脚本代码(包含一个函数调用)
  • jsonp的全名叫做json with padding,就是把json对象用符合js语法的形式包裹起来以使其他的网站可以
    请求到,也就是将json封装成js文件传过去。

十六、如何优化代码

  • 代码重用
  • 避免全局变量(命名空间,封闭空间,模块化 mvc…)
  • 拆分函数避免函数过于臃肿
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值