JS常用知识点(一)
1.js数据类型
基本类型:String、Number、boolean、null、undefined、Symbol
引用类型:Object
null和undefined的区别:undefined表示定义但未赋值。null表示定义并赋值,但值为null,可用于对象的初始化或销毁。
Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属性名,也可使用 Symbol 定义常量,可以保证这一组常量的值都不相等。
2.判断变量的类型
typeof:返回数据类型的字符串表达(不能区分Object、null和Array,都会返回'Object')。
instanceof (实例于):不能区分基本类型string和boolean,除非是(使用new方法实例产生,如:var s = new string() )字符串对象和布尔对象。
constructor :除了undefined和null,其他类型的变量均能使用constructor判断出类型。不过要注意,constructor属性是可以被修改的,会导致检测出的结果不正确。
Object.prototype.toString.call() : 目前最好用
首先在Object.prototype.toString方法被调用时,会执行下面的操作步骤:
1. 获取this对象的[[Class]]属性的值.
2. 计算出三个字符串"[object ", 第一步的操作结果Result(1), 以及 "]"连接后的新字符串.
3. 返回第二步的操作结果Result(2).
[[Class]]是一个内部属性,所有的对象(原生对象和宿主对象)都拥有该属性。
判断空对象的方法:①将对象转化为字符串,再判断该字符串是否为"{}"。②for in 循环判断。③jquery的isEmptyObject方法。
④Object.getOwnPropertyNames()方法,获取到对象中的属性名,存到一个数组中,返回数组对象,我们可以通过判断数组的length来判断此对象是否为空(此方法不兼容ie8)
⑤使用ES6的Object.keys()方法,与④方法类似,是ES6的新方法, 返回值也是对象中属性名组成的数组
3.数据类型转换
全等和相等的区别:
相等 ==: 先隐式转换类型再比较。
全等 ===:直接比较,不转换类型,只要是类型不同就不相等,类型相同的看值是否相等。
Object.is(value1,value2):ES6 提出“Same-value equality”(同值相等)算法,它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。Object.is与“===”不同之处只有两个:一是+0
不等于-0
,二是NaN
等于自身。
强制转换和隐式转换:
使用String(),Number(),Boolean()函数强制转换。
隐式转换:字符串加数字,数字就会转成字符串。数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。乘,除,大于,小于跟减的转换也是一样。
== 时候也会进行隐式转换 ①undefined == null。 ②字符串和数字比较时,字符串转数字。 ③数字为布尔比较时,布尔转数字。 ④字符串和布尔比较时,两者转数字。
基本包装类型:Boolean,Number,String 这三个基本类型都有自己对应的包装对象。包装对象,其实就是对象,有相应的属性和方法。调用方法的过程,是在后台偷偷发生的。
引用类型和基本包装对象的区别在于:生存期。引用类型所创建的对象,在执行的期间一直在内存中,而基本包装对象只是存在了一瞬间,所以我们无法直接给基本类型添加方法。
4.原型和原型链
每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型,也就是该对象构造函数的prototype属性。
每个原型本质上还是一个对象,它也有自己的原型,这样就形成了原型链。
5.闭包
在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。
或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
用途:① 封装变量和方法 ② 缓存 ③ 实现类和继承 ④ 匿名自执行函数
优点:① 希望一个变量长期存储在内存中。② 避免全局变量的污染。③ 私有成员的存在。
缺点:① 常驻内存,增加内存使用量。② 使用不当会很容易造成内存泄露。
6.call、apply和bind
call、apply、bind的作用是改变函数运行时this的指向,第一个参数都是this要指向的对象,然后用其他参数来传参。
区别:
call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面。
apply 的所有参数都必须放在一个数组里面传进去。
bind 除了返回是函数以外,它 的参数和 call 一样。
7.DOM事件流和事件委托
事件流又称为事件传播,DOM2级事件规定的事件流包括三个阶段:事件捕获阶段(capture phase)、处于目标阶段(target phase)和事件冒泡阶段(bubbling phase)。
你可以选择是在捕获阶段还是冒泡阶段绑定事件处理函数,这是通过addEventListener()方法实现的,如果这个函数的最后一个参数是true,则在捕获阶段绑定函数,反之false(默认),在冒泡阶段绑定函数。
在整个事件流的任何位置通过调用事件的 stopPropagation()
方法可以停止事件的传播过程。
事件委托顾名思义:将事件委托给另外的元素。其实就是利用DOM的事件冒泡原理,将事件绑定到目标元素的父节点。
如果要为大量的元素节点绑定事件,完美可以用事件委托完美解决,直接将事件绑定在这些元素的父节点上,只需要绑定一次,就可以在所有子节点触发事件。
最适合使用事件委托技术的事件包括click、mousedown、mouseup、keydown、keyup和keypress。
事件委托的好处: ① 提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用。② 动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。
8.Cookie和Storage
Cookie: ① 是设计用来在服务端和客户端进行信息传递的。
②cookie是以小的文本文件(<4k)形式(即纯文本),完全存在于客户端;cookie保存了登录的凭证,有了它,只需要在下次请求时带着cookie发送,就不必再重新输入用户名、密码等重新登录了。
Cookie的HttpOnly限制js通过document.cookie来访问Cookie,从而防止XSS(Cross-Site Scripting)攻击。
在RFC2109中定义的SET-COOKIE响应报头的格式为:Set-Cookie: Name = Value; Comment = value; Domain = value; Max-Age = value; Path = Value;Secure; Version = 1 * DIGIT;
Storage即浏览器本地储存(5M或更大),在较高版本的浏览器中,js提供了两种存储方式:sessionStorage和globalStorage。在H5中,用localStorage取代了globalStorage。
sessionStorage用于本地存储一个会话中的数据,这些数据只有在同一个会话中的页面才能访问,并且当会话结束后,数据也随之销毁。所以sessionStorage仅仅是会话级别的存储,而不是一种持久化的本地存储。
localStorage是持久化的本地存储,除非是通过js删除,或者清除浏览器缓存,否则数据是永远不会过期的。
浏览器的支持情况:IE7及以下版本不支持web storage,其他都支持。不过在IE5、IE6、IE7中有个userData,其实也是用于本地存储。这个持久化数据放在缓存中,只有不清理缓存,就会一直存在。
Cookie和Storage的区别:
(1) web storages和cookie的作用不同,web storage是用于本地大容量存储数据(web storage的存储量大到5MB);而cookie是用于客户端和服务端间的信息传递;
(2) web storage有setItem、getItem、removeItem、clear等方法,cookie需要我们自己来封装setCookie、getCookie、removeCookie
9.数组和对象常见的方法
数组常用方法:
1. join (原数组不受影响)
该方法可以将数组里的元素,通过指定的分隔符,以字符串的形式连接起来。
返回值:返回一个新的字符串
2. split (原数组不受影响)
该方法是用过指定的分隔符,将字符串分割成数组。
返回值:返回一个新的数组
数组的增删操作(直接改变原数组):
3. push
该方法可以在数组的最后面,添加一个或者多个元素。
返回值:返回的是添加元素后数组的长度。
4. pop
该方法可以在数组的最后面,删除一个元素。
返回值:返回的是刚才删除的元素。
5. unshift
该方法可以在数组的最前面,添加一个或者几个元素。
返回值: 返回的是添加元素后数组的长度
6. shift
该方法可以在数组的最前面,删除一个元素。
返回值: 返回的是刚才删除的元素。
数组的翻转和排序(改变数组)
7. reverse
翻转数组
8. sort
该方法可以对数组进行排序.
数组的拼接与截取(原数组不受影响)
9. concat
该方法可以把两个数组里的元素拼接成一个新的数组
返回值: 返回拼接后的新数组
1 // concat与push的区别 2 let arr1 = [1,2,3]; 3 let arr2 = [4,5,6]; 4 let arr = arr1.concat(arr2);//arr = [1,2,3,4,5,6]; 5 arr1.push(arr2);//arr1 = [1,2,3,[4,5,6]];
10. slice([start],[end])(左闭右开)
该方法可以从数组中截取指定的字段,返回出来。
返回值:返回截取出来的字段,放到新的数组中,不改变原数组。
删除或增加元素(任意在任何位置,直接改变原数组,没有返回值)
11. splice(start,count,[element,...])
从start(从0开始)下标开始,删除count个,并在该位置添加element,start开始全部往后移动。
查找元素在数组中出现的位置
12. indexOf
该方法用来查找元素在数组中第一次出现的位置,无则返回-1。
结构:
arr.indexOf(元素)
13. lastIndexOf
该方法用来查找元素最后一次在数组中出现的位置
ES5新增的遍历数组方法
1. forEach( function(item,index,arr){} )
该方法等同于for循环,没有返回值
2.map( )
映射,该方法使用和forEach大致相同,但是该方法有返回值,返回一个新数组,新数组的长度和原数组长度相等。
let arr = [1,32,54,6,543]; let res = arr.map(function(item,index,arr){ //里面的function是一个回调函数, //item: 数组中的每一项; //index:item 对应的下标索引值 //arr: 就是调用该方法的数组本身 return item*2; }) //res=[2, 64, 108, 12, 1086]
3. filter( function(item, index) {return item;} )
filter方法: 有返回值(过滤后的数组), 过滤出符合条件(回调函数返回值为true)的元素。
4. some( function(item) { return item.done; } )
判断数组中有没有符合条件的项(只要有,就返回true),如果一个都没有,才返回false。
5. every( function(item) { return item.done; } )
判断数组中所有的项是否满足要求,如果全都满足,才返回true,否则返回false。
6. find( function(item) { return item.done; } )
找到符合条件的项,并且返回第一项。
7. findIndex( function(item) { return item.done; } )
到符合条件的项的下标,并且返回第一个。
8.reduce( function(total,currentValue,[currentIndex],[arr] ){} , [initialValue] )
求和计算:
var arr1 = [1,2,3,4,5] ; var new1 = arr1.reduce(function(pre,next,index){ return pre+next ; //pre+next=10+5=15 })
扁平化数组(拼接数组):
var arr2 = [[1,2,3],[4,5],[6,7]] ; var new2 = arr2.reduce(function(pre,next,index){ return pre.concat(next); //前数组拼接后数组 .concat() })
对象数组叠加计算:
var arr3 = [ {price:10,count:1}, {price:15,count:2}, {price:10,count:3} ]; var new3 = arr3.reduce(function(pre,next,index){ return pre+next.price*next.count; },0) //在原数组第一项添加为0,不改变原数组,则可不操作第一项
对象常用方法
Object.assign(target,...sources)
用于将所有可枚举属性的值从一个或者多个源对象复制到目标对象,将返回目标对象,参数target是目标对象,参数sources是源对象。
此方法实现的是深拷贝,但是这种情况只能进行第一层的深拷贝,更深层次的拷贝还是传址的。
//第一层为深拷贝 var obj1 = { a: 1, b: 2 }; var obj2 = {}; Object.assign(obj2, obj1); obj2.a = 3; console.log(obj1, obj2); //输出结果是: {a:1,b:2} {a:3,b:2}
//第二层为浅拷贝 var obj1 = [{ a: 1, b: 2 }, 2, 3]; var obj2 = []; Object.assign(obj2, obj1); obj2[0].a = 3; console.log(obj1, obj2); // 输出的结果是:[{ a: 3, b: 2 }, 2, 3] 和 [{ a: 3, b: 2 }, 2, 3]
var obj1 = JSON.parse(JSON.stringify(obj)); //可用此方法实现深拷贝
Object.entries()
返回一个给定对象自身课枚举属性的键值对数组,其排列方式与使用for···in循环遍历该对象时返回的顺序一致(区别在于for···in循环枚举原型链中的属性)。
Objection.is(value1,value2)
判断两个值是不是相同的值。两个参数是两个需要比较的值。返回一个布尔值表示是不是相同。
Object.freeze()
方法可以冻结一个对象,一个被冻结的对象再也不能被修改,冻结了一个对象则不能向这个对象添加新的属性,不能删除该对象以有属性的可枚举性、可配置性、可写性,
以及不能修改已有属性的值,此外冻结一个对象后该对象的原型也不能被修改。返回和传入的参数相同的对象。
prototypeObj.isPrototypeOf()
用于测试一个对象是不是存在在另一个对象的原型链上。
10.new对象时内部做了什么?
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。
var obj = {}; //创建了一个空对象obj obj.__proto__ = Base.prototype; //我们将这个空对象的__proto__成员指向了Base函数对象prototype成员对象 Base.call(obj);//我们将Base函数对象的this指针替换成obj,然后再调用Base函数,于是我们就给obj对象赋值了一个id成员变量,这个成员变量的值是”base”