赞
踩
undefined、null、number、boolean、string;
基本数据类型值指保存在栈内存中的简单数据段。访问方式是按值访问。
Object、array、function、data
引用数据类型值指保存在堆内存中的对象。也就是,变量中保存的实际上的只是一个指针,这个指针指向内存中的另一个位置,该位置保存着对象。访问方式是按引用访问
1、对于string,number等基础类型,==和===是有区别的
1)不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等
2)同类型比较,直接进行“值”比较,两者结果一样
2、对于Array,Object等高级类型,==和===是没有区别的
进行“指针地址”比较
3、基础类型与高级类型,==和===是有区别的
1)对于==,将高级转化为基础类型,进行“值”比较
2)因为类型不同,===结果为false
————————————————
版权声明:本文为CSDN博主「Bliss_妍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yyychocolate/article/details/108089477
"0" == null // false
"0" == undefined // false
"0" == false // false -> 0 比较 “0” == 0 =》"0" -> 0 => 0==0 => true
"0" == NaN // false
"0" == 0 // ''0" -> 0 => 0 == 0=>0===0 => true
"0" == "" // "0" === "" => false
false == null // false null 和任意都不等(除undefined和null)
false == undefinded // false
false == NaN // false
false == 0 // false -> 0 => 0== 0 => 0===0 => true
false == "" // false -> 0 => 0 == "" => "" -> 0 => 0 == 0 => 0 === 0 => true
false == []
// false -> 0 => 0 == [] => [].toString() = '' => 0 == '' => 0 === 0 => true
false == {}
// false -> 0 => 0 == {} => Object.prototype.toString.call({})="[object Object]"
// 0=="[object Object]" = >Number( "[object Array]" ) = NaN
// => 0 == NaN => false
"" == null // false
"" == undefined //false
"" == NaN //false
"" == 0 // ''-> 0 => 0===0 => true
"" == [] // [] -> '' => ""=="" => true
"" == {} // {} -> NaN => "" == NaN => false
0 == null // false
0 == undefinded //false
0 == NaN // false
0 == [] // [] -> "" => 0 == "" => 0 == 0 => 0===0 => true
0 == {} // {} -> NaN => 0 == NaN => false
复制的是存储在栈中的指针,将指针复制到栈中未新变量分配的空间中,而这个指针副本和原指针指向存储在堆中的同一个对象;复制操作结束后,两个变量实际上将引用同一个对象。因此,在使用时,改变其中的一个变量的值,将影响另一个变量。
对象值都是引用,所以的对象的比较也叫引用的比较,当且当他们都指向同一个引用时,即都引用的同一个基对象时,它们才相等
let a=[0,1,2,3,4],
b=a
console.log(a===b); //true
a[0]=1;
console.log(a,b); [1,2,3,4] , [1,2,3,4]
let a1 = {name:'aa',age:18}
let b1 = {name:'aa',age:18}
alert(a1===b1); //false
a. 引用类型的值是可以改变的,例如对象就可以通过修改对象属性值更改对象。
b. 引用类型可以添加属性和方法。
c. 引用类型的赋值是对象引用,即声明的变量标识符,存储的只是对象的指针地址。
d. 引用类型的比较是引用(指针地址)的比较。
e. 引用类型是同时保存在栈区和堆区中的,栈区保存变量标识符和指向堆内存的地址。
浅拷贝:
只是增加了一个指针指向已存在的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深拷贝:
在计算机中开辟一块新的内存地址用于存放复制的对象。
1、for···in只循环第一层
// 只复制第一层的浅拷贝
function simpleCopy(obj1) {
var obj2 = Array.isArray(obj1) ? [] : {};
for (let i in obj1) {
obj2[i] = obj1[i];
}
return obj2;
}
var obj1 = {
a: 1,
b: 2,
c: {
d: 3
}
}
var obj2 = simpleCopy(obj1);
obj2.a = 3;
obj2.c.d = 4;
alert(obj1.a); // 1
alert(obj2.a); // 3
alert(obj1.c.d); // 4
alert(obj2.c.d); // 4
2、直接用=赋值
let a=[0,1,2,3,4],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
3、赋值与浅拷贝的区别
1、采用递归去拷贝所有层级属性
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
//所谓的递归函数就是在函数体内调用本函数
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
2、通过JSON对象来实现深拷贝
var test ={
name:{
xing:{
first:'张',
second:'李'
},
ming:'老头'
},
age :40,
friend :['隔壁老王','宋经纪','同事']
}
var result = JSON.parse(JSON.stringify(test))
result.age = 30
result.name.xing.first = '往'
result.friend.push('fdagldf;ghad')
console.dir(test)
console.dir(result)
缺点: 无法实现对对象中方法的深拷贝,会显示为undefined
3、通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array); // true为深拷贝,false为浅拷贝
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
/**
* @desc 函数防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
function debounce(func,wait,immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
简单版
function debounce(fn,wait){
let timeOut = null
return args =>{
if(timeOut) clearTimeout(timeOut)
timeOut = setTimeout(fn,wait)
}
}
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,一般有两种方式可以实现,分别是时间戳版和定时器版。
function throttle(func, wait) {
let timeout;
return function() {
let context = this;
let args = arguments;
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
防抖应用场景
文本输入搜索联想
文本输入验证(包括 Ajax 后端验证)
节流应用场景
鼠标点击
监听滚动 scroll
窗口 resize
mousemove 拖拽
(1)、攻击原理:
用户访问登录信任网站A,验证成功后会产生A的cookie
用户在没有的登出A网站的情况下访问危险网站B,而网站B诱导用户访问A并发出请求
浏览器会带着A网站产生的cookie去执行这个请求
A网站会根据用户权限去处理这个请求,这样网站B就达到了模拟用户操作的目的了
(2)、防御措施:
(1)、攻击原理:
不需要你做任何的登录认证,它会通过合法的操作(比如在url中输入、在评论框中输入),向你的页面注入脚本(可能是js、html代码块等)。
(2)、防御措施:
设置Cookie的属性为Http only,这样js就无法获取Cookie值;
严格检查表单提交的类型,并且后端服务一定要做,不能信任前段的数据;
对用户提交的数据就行Html encode处理,将其转化为HTML实体字符的普通文本;
过滤或移除特殊的HTML标签,如<script>、<iframe>等;
过滤js事件的标签,如onclick=、onfoucs=等、
(3)、分类
CSRF:需要用户先登录网站A,获取 cookie。XSS:不需要登录。
CSRF:是利用网站A本身的漏洞,去请求网站A的api。XSS:是向网站 A 注入 JS代码,然后执行 JS 里的代码,篡改网站A的内容。
arguments 是一个对应于传递给函数的参数的类数组对象
arguments[0]
arguments[1]
arguments[2]
null 用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。 null 表示"没有对象",即该处不应该有值。 null 典型用法是:
作为函数的参数,表示该函数的参数不是对象。
作为对象原型链的终点。
当声明的变量还未被初始化时,变量的默认值为 undefined。 undefined 表示"缺少值",就是此处应该有一个值,但是还没有定义。
变量被声明了,但没有赋值时,就等于 undefined。
调用函数时,应该提供的参数没有提供,该参数等于 undefined。
对象没有赋值的属性,该属性的值为 undefined。
函数没有返回值时,默认返回 undefined。
未定义的值和定义未赋值的为 undefined,null 是一种特殊的 object,NaN 是一种特殊的 number。
JavaScript 的每个对象都继承另一个父级对象,父级对象称为原型 (prototype)对象。
通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承
// 定义父类
function Parent1 () {
this.name = '陈楚',
this.age = 18
}
// 定义子类
function Child1 () {
//通过call()方法改变Child1的this指向使子类的函数体内执行父级的构造函数从而实现继承效果
Parent1.call(this)
this.address = '洪山区'
}
// 构建子类的实例s1
var s1 = new Child1()
console.log(s1.name) //陈楚
// 父类添加say方法
Parent1.prototype.say = function () {
console.log('say bye bye')
}
// 子类中直接打印这个say方法
console.log(s1.say()) //报错
总结:构造函数继承法只能实现部分继承,如果我们在父类Parent1的原型链上添加属性或者方法的时候子类的实例无法继承到。
function Parent2 () {
this.name = '祝敏',
this.age = 19,
this.play = [1,2,3]
}
// 一样在父类添加say方法
Parent2.prototype = {
say () {
console.log('say bye bye')
}
}
function Child2 () {
this.address = '硚口区'
}
// 让子类的原型直接等于父类实例
Child2.prototype = new Parent2()
// 生成两个子类的实例s2、s3
var s2 = new Child2()
var s3 = new Child2()
// s2实例继承了父类中的name属性
console.log(s2.name) //祝敏
// s2实例也同样继承了父类原型上的say方法
console.log(s2.say()) //say bye bye
// 给s2实例继承的play属性的数组中push一个新数字
s2.play.push(4)
console.log(s2.play) //[1, 2, 3, 4]
console.log(s3.play) //[1, 2, 3, 4]
总结:借助原型链实现继承虽然解决了父类原型的方法能让子类实例对象继承的问题,但是如果我们通过子类的实例对象修改父类上的属性和方法,那么所有子类的所有实例对象上的属性和方法都会被改变。
function Parent3 () {
this.name = '许风',
this.age = 20,
this.play = [4,5,6]
}
function Child3 () {
Parent3.call(this)
this.address = '江夏区'
}
Child3.prototype = new Parent3()
var s4 = new Child3()
var s5 = new Child3()
s4.play.push(7)
console.log(s4.play) // [4, 5, 6, 7]
console.log(s5.play) // [4, 5, 6]
总结:通过call()方法改变子类的this指向然后将子类的原型对象等于父类的实例,从而实现了我们想要的效果。但是确存在着两个问题,第一个问题是性能占用,在call()方法和Child3.prototype = new Parent3()两次都调用了父级的构造函数,造成了不必要的性能浪费。第二个问题等优化了第一个问题之后我们再来看。
把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。
对同类对象抽象出其共性,形成类。
类中的大多数数据,只能用本类的方法进行处理。
类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
程序流程由用户在使用中决定。
①面向对象是相对面向过程而言
②面向对象和面向过程都是一种思想
③面向过程
强调的是功能行为
关注的是解决问题需要哪些步骤
④面向对象
将功能封装进对象,强调具备了功能的对象
关注的是解决问题需要哪些对象
⑤面向对象是基于面向过程的。
多态性、 继承性、 抽象性、 封装性
强制缓存优先于协商缓存进行,
若强制缓存(Expires和Cache-Control)生效则直接使用缓存,
若不生效则进行协商缓存(Last-Modified / If-Modified-Since和Etag / If-None-Match),
协商缓存由服务器决定是否使用缓存,若协商缓存失效,
那么代表该请求的缓存失效,返回200,重新返回资源和缓存标识,
再存入浏览器缓存中;生效则返回304,继续使用缓存
根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分,分别是强缓存和协商缓存
不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且Size显示from disk cache或from memory cache。强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control。
强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,那我们如何获知服务器端内容是否已经发生了更新呢?此时我们需要用到协商缓存策略
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,协商缓存可以通过设置两种 HTTP Header 实现:Last-Modified 和 ETag 。
浏览器在第一次访问资源时,服务器返回资源的同时,在response header中添加 Last-Modified的header,值是这个资源在服务器上的最后修改时间,浏览器接收后缓存文件和header;
浏览器下一次请求这个资源,浏览器检测到有 Last-Modified这个header,于是添加If-Modified-Since这个header,值就是Last-Modified中的值;服务器再次收到这个资源请求,会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回304和空的响应体,直接从缓存读取,如果If-Modified-Since的时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和200。
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的Etag值放到request header里的If-None-Match里,服务器只需要比较客户端传来的If-None-Match跟自己服务器上该资源的ETag是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现ETag匹配不上,那么直接以常规GET 200回包形式将新的资源(当然也包括了新的ETag)发给客户端;如果ETag是一致的,则直接返回304知会客户端直接使用本地缓存即可。
首先在精确度上,Etag要优于Last-Modified。
Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;如果是负载均衡的服务器,各个服务器生成的Last-Modified也有可能不一致。
第二在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值。
第三在优先级上,服务器校验优先考虑Etag
1.频繁变动的资源
Cache-Control: no-cache
对于频繁变动的资源,首先需要使用Cache-Control: no-cache 使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效。这样的做法虽然不能节省请求数量,但是能显著减少响应数据大小。
2.不常变化的资源
Cache-Control: max-age=31536000
通常在处理这类资源时,给它们的 Cache-Control 配置一个很大的 max-age=31536000 (一年),这样浏览器之后请求相同的 URL 会命中强制缓存。而为了解决更新的问题,就需要在文件名(或者路径)中添加 hash, 版本号等动态字符,之后更改动态字符,从而达到更改引用 URL 的目的,让之前的强制缓存失效 (其实并未立即失效,只是不再使用了而已)。
在线提供的类库 (如 jquery-3.3.1.min.js, lodash.min.js 等) 均采用这个模式。
当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候,这时候是一定会发生回流的,因为要构建render tree。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。
回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流
比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变
不在布局信息改变时做 DOM 查询
使⽤ cssText 或者 className ⼀次性改变属性
使⽤ fragment
对于多次重排的元素,如动画,使⽤绝对定位脱离⽂档流,让他的改变不影响到其他元素
函数作为对象本身属性调用的时候,this 指向对象
1.call:参数1 this指向,参数2 任意类型
2.apply:参数1 this指向,参数2 数组 (参数一为null指向的是本身)
3.var一个变量保存this指向
4.使用es6的箭头函数
let obj={
a:222,
fn:function(){
console.log(this) //obj
setTimeout(function(){
console.log(this) //window
})
}
};
obj.fn();
let obj={
a:222,
fn:function(){
setTimeout(()=>{
console.log(this) //obj
console.log(this.a) //222
});
}
};
obj.fn();
//被嵌套的函数独立调用时this默认指向window
var obj = {
a:2,
foo:function(){
console.log(this) // obj
function text(){
console.log(this) //window
}
text();
}
}
obj.foo()
//自执行函数内部中的this指向window
var a = 10;
function foo(){
(function test(){
console.log(this); //window
})()
}
var obj = {
a:2,
foo:foo
}
obj.foo();
//闭包 this默认指向了window
var a = 10;
var obj = {
a:2,
foo:function(){
var c = this.a
return function test(){
console.log(this)
return c
}
}
}
var fn = obj.foo()
fn()
// 隐式丢失this的五种情况
// 1、函数赋值给另外变量
var a = 0;
function foo(){
console.log(this) //window
console.log(this.a)
}
var obj = {
a:1,
foo:foo
}
var bar = obj.foo;
bar();
//2、参数传递
var a = 0;
function foo(){
console.log(this)
}
function bar(fn){
fn()
}
var obj={
a:1,
foo:foo,
}
bar(obj.foo);
// 3、内置函数 setTimeout、setInterval第一个参数的回调函数中的this默认指向window
var a = 0;
var obj = {
a:1,
foo:function(){
console.log(this.a)
}
}
setTimeout(obj.foo, 2000)
// 4、间接调用
function foo(){
console.log(this.a)
}
var a = 0;
var obj={
a:1,
foo:foo
}
var p = {a:4};
obj.foo(); //1
(p.foo = obj.foo)(); //0
// 显式绑定
1、call,apply, bind
2、数组的forEach等方法
1.简单理解同步异步、宏任务和微任务
js是单线程的,所有的任务都要排队挨个执行,就好比做保健(执行js代码),保健师傅只有一个(单线程),顾客(js代码)需排队享受服务,排队的顺序按照顾客的种类(同步异步、宏任务微任务)和顾客到店顺序(在代码中的位置)执行;
同步与异步、宏任务和微任务分别是函数两个不同维度的描述。
异步任务:setTimeout和setInterval、ajax、事件绑定等
同步任务:除了异步任务外的所有任务
微任务:process.nextTick和 Promise后的then语句和catch语句等
宏任务:除了微任务以外的所有任务
2.执行顺序判断方法
先同步再异步,在此基础上先宏任务再微任务
setTimeout(function () {
new Promise(function (resolve, reject) {
console.log('异步宏任务promise');
resolve();
}).then(function () {
console.log('异步微任务then')
})
console.log('异步宏任务');
}, 0)
new Promise(function (resolve, reject) {
console.log('同步宏任务promise');
resolve();
}).then(function () {
console.log('同步微任务then')
})
console.log('同步宏任务')
函数声明会覆盖变量声明,但不会覆盖变量赋值
function value(){
return 1;
}
var value;
alert(typeof value); //"function"
function value(){
return 1;
}
var value = 1;
alert(typeof value); //"number"
一句话解释:
能够读取其他函数内部变量的函数。
稍全面的回答:
在js中变量的作用域属于函数作用域, 在函数执行完后,作用域就会被清理,内存也会随之被回收,但是由于闭包函数是建立在函数内部的子函数, 拥有了访问上级作用域中变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。
用处:
1、可以读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会在函数调用后被清除
应用场景
在开发中, 其实我们随处可见闭包的身影, 大部分前端 JavaScript 代码都是“事件驱动”的,即一个事件绑定的回调方法; 发送ajax请求成功|失败的回调;setTimeout的延时回调;或者一个函数内部返回另一个匿名函数,这些都是闭包的应用
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i) //10个10
}, 1000)
}
js是单线程的,在执行for循环的时候,定时器被放到任务队列中等待执行,等到定时器可以执行的时候,for循环已经跑完了,此时i的值为10,因此打印出10个10
for (var i = 0; i < 10; i++) {
((j) => {
setTimeout(function () {
console.log(j) //1-10
}, 1000)
})(i)
}
我们可以根据闭包的知识来更改一下for循环中的逻辑,利用闭包将i的值传递给a,或者如下
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i)
}
var的作用域是全局的,且有变量提升,因此for中定义一个变量,全局可以使用,循环中的每一次给变量i赋值都是给全局变量i赋值
let是块级作用域,只在代码块中起作用,在js中一个{}中的语句我们也称为叫一个代码块,每次循环会产生一个代码块,每个代码块中的都是一个新的变量
var list = document.getElementsByTagName('li')
for(var i = 0; i < list.length; i++) {
(function() {
var temp = i // 调用时局部变量
list[i].onclick = function() {
alert(temp+1)
console.log(temp+1)
}
})()
}
var user = (function(){
var __name = 'sven',
__age = 29;
return {
getUserInfo: function(){
return __name + '-' + __age;
}
}
})();
alert(user.getUserInfo());
我们用下划线来约定私有变量 __name 和 __age ,
它们被封装在闭包产生的作用域中,外部是访问不到这两个变量的,
这就避免了对全局的命令污染。
var obj = new Object("name","sansan");
我们创建出一个空对象
将构造函数的作用域赋值给了新对象,也就是说谁被new了,this就指向谁
去执行构造函数内部的代码
最终返回到this
//思路:主要是利用filter()方法过滤掉重复的元素
function ArrayToHeavy(arr) {
//过滤掉原数组中重复的数字,返回新的数组
return arr.filter((item, index)=> {
//遍历出数组中数字第一次出现的下标,与数字所在数组的下标相比较,
//为true就是第一次出现
return arr.indexOf(item) === index
})
}
let arr =[1,21,2,24,3,3,7,4,4,5,5]
console.log(ArrayToHeavy(arr))
//打印的是 1, 21, 2, 24, 3, 7, 4, 5
//思路:主要是利用indexOf()方法判断传入的数组值的是否在新数组存在,不存在就把传值push到新数组
function ArrayToHeavy(arr){
//新建一个空数组
let newArr = [];
for(var i = 0; i < arr.length; i++ ){
//遍历传入的数组,查找传入数组的值是否存在新数组中
if(newArr.indexOf(arr[i]) === -1){
//不存在就把值push到新数组
newArr.push(arr[i]);
}
}
//返回新的数组
return newArr;
}
let a = [1,1,2,3,4,5,6,4,6,8,65,77];
console.log(ArrayToHeavy(a));
//打印的是 [1, 2, 3, 4, 5, 6, 8, 65, 77]
//思路:利用双重for循环找出重复的元素,然后在使用splice()方法删除重复的一个
function ArrayToHeavy(arr) {
//遍历数组中所有的元素
for(var i = 0,len = arr.length; i < len; i++){
for(var v = i + 1; v < len; v++){
//检查是否有重复的元素
if(arr[i] === arr[v]){
//有,就从数组中去除
arr.splice(v,1);
// splice方法会改变数组长度,所以要将数组长度 len 和下标 v 减一
len--;
v--;
}
}
}
return arr
}
let a = [2,4,5,7,4,8,0,4,5,7,9,4,5,21];
console.log(ArrayToHeavy(a));
//打印 [2, 4, 5, 7, 8, 0, 9, 21]
[...new Set(arr)]
set是ES6中引入的新的数据类型。set只允许存储不重复的值,所以当你放入一个数组,它会自动去掉重复的值。
首先,我们通过原数组array创建了一个新的set,所有的重复值都被去除了。
然后,我们通过展开运算符…转换回了数组
const array = [' ', 1, 2, ' ',' ', 3];
// Step 1
const uniqueSet = new Set(array);
// Set { ' ', 1, 2, 3 }
// Step 2
const backToArray = [...uniqueSet];
// [' ', 1, 2, 3]
const array = [' ', 1, 2, ' ',' ', 3];
Array.from(new Set(array));
// [' ', 1, 2, 3]
practice = (arr) => {
return arr.reduce((prev, cur) => {
return prev.includes(cur)?prev:prev.concat(cur)
//return prev.includes(cur)?prev:[...prev,cur]
}, [])
}
cookie 是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。
cookie 数据始终在同源的 http 请求中携带(即使不需要),也会在浏览器和服务器间来回传递。
sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存。
存储大小
cookie 数据大小不能超过 4k。
sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大
有期时间
localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
sessionStorage 数据在当前浏览器窗口关闭后自动删除。
cookie 设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭。
浏览器默认的 margin 和 padding 不同。解决方案是加一个全局的 *{margin: 0; padding: 0;} 来统一。
IE下 event 对象有 event.x,event.y 属性,而 Firefox 下没有。Firefox 下有 event.pageX,event.PageY 属性,而 IE 下没有。 解决办法:var mx = event.x?event.x:event.pageX;
Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
超链接访问过后 hover 样式就不出现了,被点击访问过的超链接样式不在具有 hover 和 active 了,解决方法是改变 CSS 属性的排列顺序: L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
1、首先,在浏览器地址栏中输入url
2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。
3、若没有缓存则域名解析(DNS解析),解析获取相应的IP地址。
4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
5、握手成功后,浏览器向服务器发送http请求,请求数据包。
6、服务器处理收到的请求,将数据返回至浏览器
7、浏览器收到HTTP响应
8、读取页面内容,浏览器渲染,解析html源码
9、生成Dom树、解析css样式、js交互
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于 JavaScript 的一个子集。
数据格式简单,易于读写,占用带宽小。
格式:采用键值对。例如:{ “age‟: ‟12‟, ”name‟: ‟back‟ }
在javascript中,弱类型是指数据类型可以被忽略,一个变量可以赋不同数据类型的值。javascript是一种弱类型语言,它允许变量类型的隐式转换,允许强制类型转换等,如字符串和数值可以自动转化;而强类型语言一般不允许这么做。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。