JS基础知识点总结
提示:有一些点没有展开,有问题的地方小伙伴们自己展开哦。
一、变量类型和计算
变量类型:undefiened、String、number、boolean、object({},[],null)、function()
引用类型(a、b指针指向一个地址):对象、数组、函数
变量计算(强制类型转换):字符串拼接、== 中运算符(100 ’100’ //true, 0’ ‘ //true, null == undefined //ture)、if(a)、逻辑运算符
注意:0、false、undefined、‘’、NaN、null在if中都会强制转化成false
1.JS中使用typeof能得到哪些类型?
六种:undefiened、String、number、boolean、object({},[],null)、function(console.log)
2.何时使用 === 何时使用 == ?
If (obj.a == null) {
//这里相当于obj.a === null || obj.a === undefined jquery中的源码这么写的 其他情况全部用 ===
}
3.JS中有哪些内置函数?
–数据封装类对象 内置对象 Json Math
Object Array Boolean Number String Function Date RegExp Error
4.JS变量按照存储方式区分为哪些类型,并描述其特点?
值类型:分块存储,存储在栈中
引用类型:存储在堆中(引用类型若复制的话,为了节省内存空间 ,公用一个内存块,指针指向同一地址,即为浅拷贝 )
特点:赋值的话值类型就是简单的copy值,但是引用类型的话赋值就是变量指针的一个copy,并不是真正意义上的拷贝。
5.深浅拷贝的区别
基本数据类型的特点:直接存储在栈(stack)中的数据
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里。
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
简单理解:浅拷贝就是a与b对象指向同一块地址,一个变另一个也变。深拷贝就是自己有自己的地址,自己改变了一个属性的不影响copy者的属性。
6.如何理解JSON
JS的一个对象而已 ,就是一种数据格式 。
常用的2个api
把对象变成字符串:JSON.stringify({a:10, b:20})
把字符串变成对象:JSON.parse(‘{“a”:10, “b”:20}’)
二、原型与原型链 -构造函数
知识点:
构造函数:大写字母开头的函数是构造函数。
构造函数的扩展:
var obj = new Object(); var a = new Array; var a = new Function();
使用instaneof判断一个函数是否是一个变量的构造函数 a instanceof Object
原型规则和实例:
1).原型规则:所有的引用类型:数组、对象、函数(除了null)都具有对象的特性(obj.a = 22;)。
例如:var a = [1,2,3]; a.age = 22; a = [1,2,3,22];
2).所有的引用类型(数组、对象、函数、除了null),都有一个_proto_属性(隐式原型),属性值是一个普通的对象。
Var obj = {}; obj.a = 100; console.log(obj.proto);
3).所有的函数都有一个prototype(显式原型)属性,属性值也是一个普通的对象。
function fn () { fn.a = 100; } console.log(fn.prototype);
4).所有引用类型的_proto_属性值指向它的构造函数的”prototype“属性值 console.log(obj.proto === Object.prototype); //true 隐式原型等于构造函数的显式原型 Object是obj的构造函数
5)当试图得到一个对象的某个属性时(如图15行),如果这个对象没有这个属性,那么会去它的_proto_(即他的构造函数的prototype)中寻找。
Var item;
For(item in f) {//浏览器自动屏蔽了来自原型的属性,但是还是建议加上这个判断,保证了程序的健壮性。
If (f.hasOwenOperty(item)) { console.log(item); }
}
上图的代码再加一行:16行:f.toString();
原型链:
Instanceof
用于判断引用类型属于哪一个构造函数的方法。
1.如何准确判断一个变量是数组类型?
Var arr = [] ;
typeof varr ; //Object
varr instanceof Array;//true
2.写一个原型链继承的例子
写一个dom封装查询的例子
3.描述new一个对象的过程
创建一个新对象;this指向这个新对象; 执行代码,即对this赋值;返回this;
4.Zepto(或其他框架)源码中如何使用原型链
5.作用域和闭包
知识点:
1)执行上下文:
Console.log(a); //undefined
Var a = 100;
范围:一段函数或者一个函数
全局:变量定义 变量声明
函数:变量声明、变量声明、this、arguments
2)this:
this要在执行时确认,定义时是无法确认。
作为构造函数执行
作为对象属性执行
作为普通对象执行
Call apply bind
Call:
function fn1 (name) {alert(name); console.log(this);}
fn1.call({x:5}, ‘zhangsan’); //第一个参数为修改this指向的内容 否则this指向window
Bind: 与call超级类似。
Var fn2 = Fucntion fn2 (name) {alert(name); console.log(this);}.bind({x:5});
Fn2.call({x:5}, ‘zhangsan’); //修改的方式不一样而已
举一个例子
var name = '雄安王'
var age =17
var obj = {
name:'校长',
objAge:this.age,
myFun:function(){console.log(this.name+'年龄'+this.age)
}
}
obj.objAge //17
obj.myFun() //校长年龄undefined
//第二个this指向的是window
var db = {name:'‘德玛’, age:99}
obj.myFun.call(db); // 德玛年龄 99
obj.myFun.apply(db); // 德玛年龄 99
obj.myFun.bind(db)(); // 德玛年龄 99
bind 方法后面多了个 () 外 ,结果返回都一致!
bind 返回的是一个新的函数,你必须调用它才会被执行。
在传多参数的情况下apply是一个数组 call和bind都是正常的参数之间逗号隔开
作用域:
js没有块级作用域,只有函数和全局作用域
自动全局
如果您为尚未声明的变量赋值,此变量会自动成为全局变量。
这段代码将声明一个全局变量 carName,即使在函数内进行了赋值。
```javascript
myFunction();
// 此处的代码能够使用 carName 变量
function myFunction() {
carName = "porsche";
}
var num = 123;
function foo(){
var num = 456;
function fn(){
console.log(num); // 输出456
};
fn();
}
foo();
预解析 : 变量名num和函数名foo声明提升,函数名foo和函数体链接
执行代码:
num = 123, 赋值
执行函数, 函数内部声明提升,变量名num和函数名fn
变量num=456, 执行函数fn
输出num, fn函数内部没有num,向上级寻找
num=456, 输出num
if(true) {var name = ‘zhangsan’; }console.log(name)
作用域链:当前作用域没找到定义的变量,就会像父级寻找这个变量。
闭包:作用域的定义时候的作用域 而不是执行时候的作用域
闭包的使用场景:函数作为返回值 函数作为参数传递
1.说一下变量提升的理解
变量的定义 函数的声明(注意和函数表达式的区别)
例如:
a(); function a() {console.log(‘dd’)} //dd
d(); var d = function () {console.log(‘ff’)} //报错
例如:
Fn(); //后声明,可以执行
Function fn() {}
Fn1() ; //后声明,无法执行
Var fn1 = Function() {}
因为代买首先预解释只发生在"="的左边,只把左边的进行预解释,右边的是值是不进行预解释的 所以就会认为 fn1函数并没有定义
2.说明this的使用场景?
作为构造函数的执行(this->调用的对象) 、作为对象属性的执行(该对象)、 作为普通函数的执行(this->window)、call apply bind
3.创建10个a便签。点击的弹出来对应的序号
4.如何理解作用域?
自由变量 作用域链,即自由变量的查找 闭包的两个场景
5.实际开发中的闭包的应用
闭包实际应用中主要用于封装变量,收敛权限。
声明在一个函数中的函数,叫做闭包函数
第四章:异步和单线程
知识点:
什么是异步?对比同步 :有没有阻塞成为界限 同步的话等待时间太长了
前端使用异步的场景:有等待发生的情况需要异步
定时任务:setTimeout, setInterval
网络请求:ajax请求,动态img加载
事件绑定
异步和单线程
异步就是,setTimeout会被拿出去放一边等着(暂存),单线程不能同时做两个事情,正常的函数执行完了,空闲了,在执行这个一边(暂存)的函数。单线程:一个一个排队来,那个程序来了就执行那个程序。
另一种解释:同步,就是调用某个东西是,调用方得等待这个调用返回结果才能继续往后执行。异步,和同步相反 调用方不会理解得到结果,而是在调用发出后调用者可用继续执行后续操作,被调用者通过状体来通知调用者,或者通过回掉函数来处理这个调用
举一个例子:
你去商城买东西,你看上了一款手机,能和店家说你一个这款手机,他就去仓库拿货,你得在店里等着,不能离开,这叫做同步。现在你买手机赶时髦直接去京东下单,下单完成后你就可用做其他时间(追剧、打王者、lol)等货到了去签收就ok了.这就叫异步。
1.同步和异步的区别是什么?分别举一个同步和异步的例子
区别:同步会阻塞代码,异步不会。 alert是同步,setTimeout是异步。
2.一个关于setTmeOut的笔试题
3.前端使用的异步的场景有哪些
定时任务:setTimeout, setInterval
网络请求:ajax请求,动态img加载
事件绑定
这三种时间都需要等待,之所以要用异步是因为不能等待,等待就会卡顿,阻塞,这些都是因为js是一个单线程的语言决定的,只允许同时做一件事情,如果想要同时做多个,其他的事件都必须要去一边排队,先做好一件事情,把一件事情做好再做其他的事件,这是一个串行的过程。
第五部分: 日期和math
日期:注意getMonth()输出的是0-11月 所以不要忘记+1
Math :获取随机数Math.random();
场景:清楚缓存 random返回大于0小于的的一个小数。很强频繁访问一个链接,在链接后加一个random随之改变,清除缓存。
数组api:
forEach:遍历所有数组。
every:判断所有元素是否符合条件。
some:判断数组至少有一个满足条件。var b = a.some(function (item,index) { if () Return true })
Sort:排序。
var a = [1,4,3,5,6]; var b = a.sort((a,b)=>{return a-b}) //从小到大排序
map:对数组进行重新拼装,组合成新数组。
Var a = [1,2,3,4,5]; var b = a.map(function (item,index) {return ‘’+item+})
filter:过滤符合条件的元素。
Var a = [1,2,4]; var b = a.filter(function(item,index) {if(item>=2){return true;}})
对象api
Var obj = {x:100,y:200,z:300}
var key;
for(key in obj) { if (obj.hasOwnOperity(key)) { console.log(key,obj[key]) ; } } //判断该属性是不是该对象的原生属性,而不是从原型链中继承下来的。
题目:
1.获取 2017-06-10格式的日期
2.获取随机数,要求是长度一致的字符串格式
3.写一个能遍历对象和数组的通用forEach函数
JS-Web-API
Window与document其实是浏览器内置的 js需要遵守的,比如nodejs不跑在浏览器上,所以就没有这些内置的对象,但是会有一些服务器相关的对象。
DOM的本质:D:document O:Object M:model
本质:根源:xml可以描述任何结构性的语言,标签的名字可以自定义。
节点操作 document.querySelectorAll(‘p’)//集合
Property:
- var obj = {x:100,y:200} console.log(obj.x);
- var p = document.getElementByTagName(‘p’)[0]; Console.log(p.nodeName); //p
Attribute:
q.getAttribute(‘style’);
q.setAttribute(‘style’, ‘color:black;’)
dom结构:
新增节点 获取父元素 var parent = p1.parentElement
获取子元素 var child = p1.childNodes
删除节点 p1.removeChild(child[0]);
问题:
1.DOM是哪种数据结构?
树形结构
2.DOM常用的api有哪些呀?
获取dom节点 以及节点的property和Attribute 获取父节点 获取子节点 新增节点 删除节点。
3.4.DOM节点的attr和property 有何区别?
Property只是一个JS对象的属性修改。
Attribute是对html标签属性的修改。
4.BOM操作
全称:Broswer Object Model
知识点:
Navigator :
var us = navigator.userAgent; var isChrome = us.indexOf(‘chrome’); console.log(isChrome);
screen : screen.width screen.height
Location:
console.log(location.href) ;//location.protocal; location.host; location.pathname; locaton.hash; location.href;
History:history.back(); //fowrord
如何检测浏览器的类型?
拆除url的各部分
事件:
知识点:
通用事件的绑定
事件冒泡:e.stopPropogation(); //取消冒泡
事件传播分成三个阶段:
捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获阶段”(capture phase),捕获阶段不会响应任何事件;
目标阶段:在目标节点上触发,称为“目标阶段”
冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层;
事件代理:
事件代理(Event Delegation),又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
代理:多个a标签需要代理
Div1.addEventListener(‘click’, function(e){
Var target = e.target;
If(target.nodeName === ‘A’) {
Alert(target.innerHTML);}
})
优点:
事件委托对于web应用程序带来的几个优点:
1.管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。
2.可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。
3.因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。
题目:
1.编写一个通用的事件监听函数
2.描述时间的冒泡流程:Dom数型结构 事件冒泡 阻止冒泡 冒泡的应用
3.对一个无线下拉加载图片的页面,如给每个图片绑定事件?
使用代理 好处:代码简洁绑定一次 浏览器的压力比较小。
Ajax
知识点:
XMLHttpRequest
状态码说明 :
1.还没有调用send(),未初始化
2.载入 已调用了send()方法,正在发送请求。
3.载入完成,send方法执行完成,已经收到了响应的全部内容。
4.完成 响应内容解析完成,可以在客户端可以调用了。
向服务器请求得到的States:
200-表示请求完成
300-需要重定向
404-客户端请求错误
504 服务器错误
500 服务器错误
跨域:
浏览器有同源策略,不允许ajax访问其他域接口
协议、域名、端口有一个不一样就算跨域。 hhtp默认端口80 https默认端口43
可以跨域的标签:img link script
题目:
手动编写一个ajax,不依赖第三方库。
跨域的几种实现方式。
开发环境
Webstorm sublime vscode atom
插件:
常用的git的命令:
git add . //提交
Git checkout 文件 //还原文件
Git commit -m “vvv” //将改的东西提交到本地仓库
Git push origin master //把他提交到远程的仓库 服务器上
Git pull origin master //另一个人就pull下载下来你修改的东西
Git branch //分支
Git checkout -b xx //新建一个分支
Git checkout xxx //切换到一个已有的分支
Git merge xxx //把之前改的都拷贝到这个分支上
将项目发布到git上的基本步骤:这里用的是国内对的网站coding.net
mkdir 文件名字
cd 文件名字
git init
echo “# js-git-test” >> README.md
git add README.md
git commit -m “first commit”
git remote and origin 网站上复制下来的密钥ssh
git push -u origin master
AMD
异步加载 使用 define require文件等
CommonJS 同步 module.export={}
使用场景:
需要异步加载js,使用AMD
使用了npm之后,建议使用CommonJS
页面的渲染
知识点:
1.加载资源的形式
输入url或跳转页面,即:加载html
加载html中的静态资源script css img等媒体文件(异步加载)
2.加载一个资源的过程
浏览器根据DNS服务器得到域名的IP地址
像这个IP的机器(对应的服务器)发送http请求
服务器手打、处理并返回http请求
3.浏览器渲染页面的过程
根据HTML结构生成DOM Tree(无样式)
根据css生成cssOM
将DOM和CSSOM整合成一个RenderTree(节点已经有了样式)
浏览器根据RenderTree 开始渲染和展示
遇到script时,会执行并阻塞渲染
问题:
为什么把css放到head中?
不放到head中会让页面出现卡顿,性能太差,放在head中可以先加载,让页面中的样式一次加载出来,而不是放在最后,页面先按照默认方式加载,执行到页面底端发现了css文件后,再去修改页面已经渲染好了的样式。
为什么要把script放到body最后的位置?
因为放在最后他不会阻塞(放到中间的话浏览器遇到他就会停下来解析js)所以放在最后的话不会发生阻塞,先把html的便签先渲染出来,这样不会出现阻塞,会使页面的效率更高。
window.onload与DOMContentLoaded的区别?
页面的性能问题。
Window.addEventListener(‘load’, function() {
})//页面的加载资源加载完才会执行,包括图片,视频等
Document.addEventListener(‘DOMContentLoaded’, function() {
})//DOM渲染完即可执行,此时的图片、视频还可能没有加载完。
性能优化
原则:
多使用内存、缓存或者其他方法。
减少cpu计算、较少网络。
从哪里入手?
1.加载页面静态资源
加载资源优化:静态资源的压缩合并、静态资源缓存(缓存:通过连接名控制缓存)、使用CDN(CDN:bootcss.CDN )让资源加载更快、使用SSR后端渲染(现在vue、react都提出了这样的概念。其实jsp、php、asp都属于后端渲染,数据直接输出到HTML中)、懒加载。
2.页面的渲染
Css放在前面,JS放在后面、懒加载(图片懒加载、下拉加载更多)
3.减少DOm查询,对DOM查询做缓存
4.减少DOM操作,多个操作尽量合并在一起执行:
减少dom操作:缓存DOM查询、合并DOM插入
合并DOM插入:定义一个片段,将片段添加10个li最后一次插入到listNode后面
5.事件节流:
6.尽早执行操作(DOMContentLoaded)
安全问题
知识点:
XSS跨站请求攻击:恶意攻击者在web页面中会插入一些恶意的script代码。当用户浏览该页面的时候,那么嵌入到web页面中script代码会执行,因此会达到恶意攻击用户的目的。
盗取cookie 预防:替换关键字 把<替换为 < >替换为> 或者后端替换
XSRP 跨站请求伪造
预防:增加验证流程,如输入指纹、密码、短信验证码。