js 小知识

575 阅读9分钟
a{blr:expression(this.onFocus=this.blur());}清除 A 链接在点击时会产生虚线的问题.<a href="link1.htm" onfocus="this.blur()">link1</a>

input {star : expression(onmouseover=function()
{this.style.backgroundColor="#FF0000"},

onmouseout=function(){this.style.backgroundColor="#FFFFFF"}) }
一般不建议使用expression,因为expression对浏览器资源要求比较高。

.ECMAScript的值
ECMAScript中变量可以存在两种类型的值,即原始值和引用值。
原始值:
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
引用值:
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
.ECMAScript 有 5 种原始类型(primitive type),即 Undefined、Null、Boolean、Number 和 String。
Boolean Number String 的类型(type of)是 "function",undefined是自身,null是'object'
原始类型:原始类型占据的空间是固定的,所以可将值存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。

.js对象(9个)Array,Boolean,Date,Math,Number,String,RegExp,Functions(JS全局对象,顶层函数(全局函数)),Events;
Browser对象(5个):Window,Navigator,Screen,History,Location;
DOM对象(4):document,element,attribute,event

.从一个网站链接到另外一个网站会产生新的http请求,referrer是http请求中表示来源的字段。
no-referrer-when-downgrade表示从https协议降为http协议时不发送referrer给跳转网站的服务器。

.浏览器运行加载页面机制:
浏览器的主要组件包括:
用户界面- 包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分。
浏览器引擎- 用来查询及操作渲染引擎的接口。
渲染引擎- 用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来。
网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作
UI 后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口。
JS解释器- 用来解释执行JS代码。

.渲染引擎在取得内容之后的基本流程:
解析html以构建dom树->构建render树->布局render树->绘制render树

.网站显示正在等待可用的套接字符(sockets):
   (套接字:相当于一部电话)
服务器需要创建一个监听套接字,用于监听浏览器发送过来的请求。
浏览器也同样要创建一个套接字监听服务器返回消息;
360极速模式使用chrome内核,Chrome对同一个域名的sockets连接数作了限制,打开网页过多,连接数被消耗完了
服务器忙,没有空闲的套接字响应浏览器;

.一个对象获取数组中的值,此对象自动补全键(等于数组元素)

            var arr = ['哈哈', '哈1哈'];
                var obj = {}, newArr = [];
                    for (var i = 0, j = arr.length; i < j; i++) {
                        if (!obj[arr[i]]) {
                            newArr.push(arr[i]);
                            obj[arr[i]] = arr[i];
                        }
                }
obj[arr[i]]  //此对象自动补全键(等于数组元素)
 
跨作用域取值(闭包):
    function a () {
        return function () {
            alert(02)
        }   //return 到b函数中的a() c再执行a
    }
    b();
    function b() {
        let c = a();
        c();
    }

    //自调函数
op.innerHTML = function () {
    return '111111'
  }()

 .网页版切换手机版
     try {
            if (!window.location.hash.match("fromapp")) {
                if ((navigator.userAgent.match(/(iPhone|iPod|Android|ios|iPad|Nokia|SymbianOS|Windows Phone|Linux armv71|WindowsCE|BlackBerry|IEMobile|Nexus10|Nexus4|Nexus5|Nexus5X|Nexu6|Nexus6p|Nexus7|Nokia Lunia520|Nokia N9|iPad Mini|iphone4|Galaxy S5|pixel2|pixel 2 XL|iPhone X)/i))) {
                    window.location = "wap网址";
                }
            }
        }
        catch (err) {
            console.log(404);
        }
        
        
    .网页中防止图片丢失,一张图替换丢失的
  
         function imss() {
 var img = event.srcElement;//调用内置事件的srcElement属性
 img.src = "http://beijing.xuefu.com/zt/img/bj4-1.png";
 img.onerror = null;//阻止图片闪动
    }
 <img src="images/logo.png" onerror="imss();" />
 
 .js中的轮询:
短轮询指的是在客户端上写一段js,设置一个间隔时间段不断的向服务器请求资源
长轮询,客户端的逻辑不变,变的是服务器的逻辑,当一个请求来的时候,服务器不会立刻响应该请求,而是会把该请求挂起,等到数据有变化的时候才会把数据库返回给客户端
.来个简易事件冒泡:

      let oop =  document.querySelector('#oop');
      oop.addEventListener('click',fun);
      function fun (e) {
          e = e || window.event;
          if(e.target.tagName.toLowerCase() === 'a') {
              console.log(e.target.innerText);
          }
      }
    //   类似这种的循环输操作子元素的事件,可用事件委托高性能的处理
.经典面试题,for循环中调用setTimeout() 
    涉及了异步、作用域、闭包
    

***for ( var i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, 1000 ); //输出5次6
}
 为什么输出5次6;
 原因如下:
 setTimeout(是个异步函数)是异步执行,1s后往任务队列里面添加一个任务,只有主线上的全部执行
 完,才会执行任务队列里的任务,当主线程执行完成后,i是6,所以此时再去执行任务
 队列里的任务时,i全部是6了。
 对于打印5次6是:
 每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是
 被放到了任务队列里面,等待执行,for循环了4次,就放了4次,当主线程执行完成
 后,才进入任务队列里面执行。

首先因为 setTimeout 是个异步函数,所以会先把循环全部执行完毕,这时候 i 就是6了,所以会输出一堆6。
解决方法:
闭包:
for (var i = 1; i <= 5; i++) {
  (function(j) {  //将每次递增的值保存在内存中
    setTimeout(function timer() {
      console.log(j);
    }, 1000);
  })(i);
}

使用 setTimeout 的第三个参数:
for ( var i=1; i<=5; i++) {
	setTimeout( function timer(j) {
		console.log( j );
	}, 1000, i);
}

使用 let 定义 i:
for ( let i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, 1000 );
}

.对象数组去重:
 var arr = [
            { id: 1 }, { id: 1 },

        ];
        var result = [];
        var obj = {};
        for (var i = 0; i < arr.length; i++) {
            if (!obj[arr[i].id]) {
                result.push(arr[i]);
                obj[arr[i].id] = true;  //去重后改变布尔值
            }
        }

将一个数字拆成数组:Array.from({length:3}).map((val,i)=>i+1) //[1,2,3]

利用with改变作用域这一特性,快速插入节点元素
  with (document)0[(getElementsByTagName('head')[0] || body).appendChild(createElement('div'))]

 ---------------------------------token: 
 Token 是在服务端产生的,如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位,如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。 
 https://www.cnblogs.com/xuxinstyle/p/9675541.html
https://segmentfault.com/a/1190000014527692?utm_source=tag-newest
 https://www.cnblogs.com/huangsheng/p/10736796.html#acp1
 解决: 
 Token完全由应用管理,所以它可以避开同源策略 
 Token可以避免 CSRF 攻击 
 Token可以是无状态的,可以在多个服务间共享;
前端使用的流程:
1.客户端使用用户名密码登录。
2.服务端收到请求,去验证用户名与密码。验证成功后,服务端会签发一个 Token,把这个 Token 发送给客户端。
3.客户端将收到的Token存储起来。(cookie或者localStorage)
4.客户端每次需要登录验证的请求都需要带着Token发送给服务器端。
5.服务器端收到请求后先验证Token,如果成功,返回数据。
 
1.服务端签发的下来的token,将其存储到cookie或者其他
  localStorage.setItem('token', data.data.token);

2. 每次发送请求都携带本地的token去发送
&emsp;&emsp;function getToken(){
&emsp;&emsp;if(!!localStorage.getItem('token')){
&emsp;&emsp;&emsp;&emsp;return localStorage.getItem('token');
&emsp;&emsp;}

&emsp;&emsp;return null;//如果获取不到token就发送null给服务器端
}
3. token 过期处理
function handleTokenFailed(code){
        if(code==401){
            localStorage.clear();
            new Toast().showMsg('登录信息已过期,请重新登录',500)
            setTimeout(function () { 
                location.href = 'index.html';
             },1000)

        }
    }
     .网站登录图片验证码的作用:
 
![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/2/1709a86aa4a82a38~tplv-t2oaga2asx-image.image)
验证码作用分析:<br>
验证码起源:因为攻击者会使用有害程序注册大量的 Web 服务帐户(如 Passport)。攻击者可以使用这些帐户为其他的用户制造麻烦,如发送垃圾邮件或通过同时反复登录多个帐户来延缓服务的速度。在大多数情况下,自动注册程序不能识别此图片中的字符。简单的说呢,就是防止攻击者编写程序,自动注册,重复登录暴力破解密码。验证码技术应运而生。
验证码实现流程:服务器端随机生成验证码字符串,保存在内存中,并写入图片,发送给浏览器端显示,浏览器端输入验证码图片上字符,然后提交服务器端,提交的字符和服务器端保存的该字符比较是否一致。一致就继续,否则返回提示。攻击者编写的robot程序,很难识别验证码字符,顺利的完成自动注册,登录。。。。。。。。。而用户可以识别填写,所以这就实现了阻挡攻击的作用。而图片的字符识别,就是看图片上的干扰强度了。就实际的效果来说,验证码只是增加攻击者的难度,而不可能完全的防止。

.js模块化写法
模块化 

var modules1 = (function () {
 
            function fn1 () {console.log(21)}
            return {
                fn1
         }
        
})()
        modules1.fn1();

(function(window) {
    let data = '123456';
    function foo() {
      console.log(12);
      
    }
    
    //暴露行为
    window.mo = { foo };
})(window);
 mo.foo();
 
.函数嵌套传参方式
let a= function (str) {
console.log(str)
return function (s) {
console.log(s)
}
}
a('a')('b') //a b

**bind改变this作用域
fn.bind(obj, args)
bind()方法会创建一个函数,该函数的this指向了传入的第一个参数,当bind()的参数为空时,this指向全局对象。如浏览器中的window。

let a = {
    b:1,
    c () {
         this.b //1
        function d () {
            return this.b //undefined
        },
        //用bind给函数绑定this改变当前函数的作用域
        function e () {
              this.b  //1
        }.bind(this);
        e()
        或者e.bind(this)()
    }
}

创建一个公用的改变this的函数:
var bind = Function.prototype.call.bind(Function.prototype.bind);//;公用
var hello = function(){
  console.log(this.name);
};

var boo = {
  name: '哈哈'
};

bind(hello, boo)(); /哈哈

函数柯里化

维基百科上说道:柯里化,英语:Currying(果然是满满的英译中的既视感),是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
function ads(x) {
    return function (y) {
        return x + y
    }
}

ads(1, 2) //3
实际上就是把add函数的x,y两个参数变成了先用一个函数接收x然后返回一个函数去处理y参数。现在思路应该就比较清晰了,就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。

_____________________________________

常用面试题:

Object.defineProperty()

知识点收藏:

js基本
常见js error
常用谷歌插件
Chrome Devtools 高级调试指南
Chrome Devtools 高级调试指南1
前端处理异常常用
总结异步编程的6种方式
数组基本