• JS高级(摘自简书)


    JS高级

    1. 访问对象属性(方法也是属性)的通用方式:obj['属性名']
        1. 属性名包含特殊字符,如"-"、空格,访问:obj['content-type']
        2. 属性名不确定:var name='age';  var value=18;  obj[name]=value
    2. IIFE:立即执行函数,用于隐藏实现、避免污染全局命名空间、编写JS模块
        (function(){ ... })() ---> 即匿名函数自调用
    3. this的指向
        1. 任何函数本质上都是通过某个对象来调用的,如果没有显式指定,则默认是window;
        2. 所有函数内部都有一个变量this,指向当前调用函数的对象;
        3. functionName.call()/apply():第一个参数用于指定函数内部this的指向。
    4. JS语句可以不加分号,但有2种情况必须加分号:
        1. 小括号开头的前一条语句;
        var a = 3;
        (function() { ... })()
        2. 中方括号开头的前一条语句;
        var b = 4;
        [1, 3].forEach(function)
        3. 为了避免这2种错误,可以在行首加分号:;(function() { ... })()
    

    原型

    function Test() { ... }
    1. prototype:显式原型(属性)
        1. 定义函数时自动添加一个prototype属性,默认指向一个Object空对象,即原型对象;
        Test.prototype instanceof Object --> true
        Function.prototype instanceof Object --> true
        Object.prototype instanceof Object --> false,Object除外
        2. 原型对象中又有一个属性constructor,指向函数自身;
        Test.prototype.constructor === Test ---> true
        3. 给原型对象添加属性/方法,函数的所有实例对象自动拥有原型对象中的属性/方法。
    2. __proto__:隐式原型(属性),ES6之前不能直接操作该属性
        1. 创建实例对象时自动添加一个__proto__属性,默认值为构造函数的prototype属性值;
        即:实例对象的隐式原型和构造函数的显式原型指向同一个原型对象;
        var tes = new Test();
        tes.__proto__ === Test.prototype ---> true
        2. 函数也有隐式原型,而且所有函数(包括Object和Function)都是Function的实例;
        Test/Object/Function.__proto__ === Function.prototype ---> true
    3. 原型链:__proto__链
        1. 原型对象中也有隐式原型__proto__,指向当前构造函数的父构造函数的原型对象;
        tes.show() --> 自身 --> 沿着__proto__查找:tes.__proto__ 即Test.prototype 
        --> Test.prototype.__proto__ 即Object.prototype --> show()不存在,报错;
        2. 所有对象/构造函数,包括Function,都直接/间接派生自Object,它是JS的顶层父类,
        其原型对象就是原型链的尽头,因为Object.prototype.__proto__ === null
    4. 访问对象属性/方法时,会自动到原型链上查找;而设置对象的属性值时,则不会涉及原型链,
       如果对象中没有该属性/方法,则添加,否则就修改;
    5. 一般情况下,方法定义在原型中,属性直接定义在通过构造函数;
    6. A instanceof B 的判断的标准:如果B的显示原型在A的原型链上,则返回true.
    

    函数高级

    1. 全局执行上下文
        1. 在执行全局代码前,将window确定为全局执行上下文;
        2. 对全局数据进行预处理:var定义的全局变量会被提前声明(值为undefined),全局函数
        会被提前定义,并把全局变量/函数添加为window的属性/方法;
        3. this指向window;
        4. 在执行代码时,才会对变量重新赋值,而定义函数的代码会直接跳过,因为在执行全局
        代码之前,函数已经被提前定义了。
        var test = 1;
        function test() { ... }
        test(); ---> 报错:test is not a function
        5. 真正的执行过程:
        var test; --> function test() { ... } --> test = 1; --> test();
    2. 函数执行上下文
        1. 调用函数、准备执行函数之前,创建对应的函数执行上下文;
        2. 对局部数据做预处理:变量的提前声明,函数的提前定义,this的指向,形参的赋值等;
    3. 闭包:内部函数引用外部函数的局部变量,外部函数执行完后,其局部变量仍存活于内存中;
        function out() {
            var a = 2;
            function inner() {
                console.log(++a);
            }
            return inner;
        }
        1. var f = out(); --> 变量f持有内函数inner()的引用,所以局部变量a仍在内存中;
        2. out(); --> 没有任何引用内函数指向inner(),那么inner将成为垃圾对象,并被GC;
        也即,局部变量a也不存在了;
        3. 闭包的生命周期:在函数内部定义时就已经产生了,在内部函数成为垃圾对象时死亡;
        var f = out(); --> f(); --> f = null; --> 死亡,释放内存;
        4. 闭包容易造成内存泄露,应该及时释放。
    4. 利用闭包自定义JS模块-1:myModule.js
        function myModule() {
            var msg = 1;
            function showMsg() { ... }
            return showMsg; --> 向外暴露
        }
        在html中引用:<script src="myModule.js" type="text/javascript">      
        var fn = myModule(); --> fn指向内部函数showMsg() --> 执行showMsg():fn();
        如果暴露多个函数,则返回一个对象:return { showMsg: showMsg, }
        var module = myModule(); --> 执行showMsg():module.showMsg();
    5. 利用闭包自定义JS模块-2:myModule.js
        (function(w) {  --> 自执行函数
            var msg = 1;
            function showMsg() { ... }
            w.myModule = { showMsg: showMsg, } --> 向外暴露
        })(window) --> 为全局上下文window添加属性myModule
        在html中引用:<script src="myModule.js" type="text/javascript">      
        myModule.showMsg(); --> myModule是window的属性,可以直接使用;
    

    对象高级

    1. 创建对象:
        1. Object构造函数模式:var obj = new Object(); --> 然后为对象添加属性/方法;
        2. 对象字面量模式:var obj = { ...(属性/方法) }
        3. 工厂模式:动态返回一个对象的函数;
        4. 自定义构造函数模式:var obj = new Person('Mack')
        function Person(name) {
            this.name = name;
            this.show = function() { ... }
        }
        5. 构造函数+原型的组合模式:
        function Person(name) { this.name=name; }
        Person.prototype.show = function() { ... } --> 公共的方法定义在原型对象中
    2. 原型链继承:子类的原型是父类的一个原型对象;
        1. 定义父类构造函数,并在原型中添加方法;
        function Supper() { this.supProp = 'Supper property'; }
        Supper.prototype.showSupper = function() { ... }
        2. 定义子类构造函数,让子类的原型指向父类对象,修正子类原型对象中的constructor,
        让其指向子类构造函数,然后为子类的原型添加方法;
        function Sub() { this.subProp = 'Sub property'; }
        Sub.prototype = new Supper(); --> 更改显示原型的指向
        Sub.prototype.constructor = Sub; --> 修正constructor的指向
        //Sub.prototype.__proto__即new Supper().__proto__,指向Supper.prototype
        Sub.prototype.showSub = function() { ... }
        3. 创建子类的对象,可以调用父类的方法:var sub = new Sub();
        sub.showSubProp(); sub.showSupperProp();
    

    本地存储

    cookie,H5新增的localStorage、sessionStorage
    

    cookie

    1. 存储在浏览器的一段文本信息,最大容量4k,在同源的http请求时携带传递,损耗带宽;
    2. cookie是在服务器端设置的,浏览器接收到cookie信息,便以键-值的形式存储在本地;
    3. 出于安全考虑,跨域名请求不会携带cookie,这是由浏览器技术实现的安全策略;
    4. 可设置访问路径和过期时间,只有此路径及其子路径才能访问此cookie。
    

    localStorage

    1. 容量最小5M,不会在http请求时携带传递,不需要服务器环境;
    2. 在所有同源窗口中共享,数据始终有效,除非人为删除,可作为长期数据;
    3. 设置:localStorage.setItem('key', 'value'); localStorage.key = value;
    4. 获取:localStorage.getItem('key');  localStorage.key;
    5. 删除:localStorage.removeItem('key');
    

    sessionStorage

    1. 容量最小5M,不会在http请求时携带传递,在同源的当前窗口关闭前有效;
    2. 与localStorage合称为Web Storage,支持事件通知机制,可以将数据更新通知监听者;
    3. iPhone的无痕浏览不支持Web Storage,只能用cookie.
    

    JS与后台通信

    AJAX:同源策略

    1. JS原生支持AJAX,目的是让JS发送HTTP请求,且AJAX通信的过程是异步的;
    2. 同源策略:基于安全考虑,AJAX只能请求同一域名下的资源,通常是JSON数据;
    报错特征:No 'Access-Control-Allow-Origin' header is present 
    on the requested resource. Origin 'null' is therefore not allowed access.
    3. AJAX执行的是同源策略,所以请求的url不需要域名,比如 url: 'js/user.json';
    

    JSONP:跨域请求

    1. 原理:<script src="..."> src链接的地址不受限制;
    2. 在页面上定义的JS函数,script-src链接的外部JS文件也可以调用,那么,外部JS就可以
       把数据以回调参数的形式传递回当前页面。
    

    移动端JS事件

    1. 移动端主要用手指操作,在JS中对应Touch事件:
        1. touchstart/touchend/touchmove:手指放到屏幕上/离开屏幕/滑动时触发;
        2. touchcancel:系统取消Touch事件时触发;
        3. 移动端一般操作:点击、滑动、拖动,这三种操作一般组合使用Touch事件完成。
    2. zeptojs:最初是为移动端提供一个精简的、类似jQuery的JS库,现在发展成一个轻量级的、
       针对现代高级浏览器的JS库;
        1. API类也似于jQuery,比如$(function(){ ... })、$(this)、$('#div') ...
        2. 其touch模块封装了移动端常用的Touch事件,针对开发移动端的特定效果。
    3. swiper.js:一个成熟稳定的、应用于PC端和移动端的滑动效果插件;
        1. 一般用来触屏焦点图、触屏整屏滚动、幻灯片等效果;
        2. 2.x版本支持低版本浏览器IE7,3.x放弃低版本浏览器,适用于移动端。
    

    进程与线程

    1. 作为浏览器脚本语言,JS主要与用户交互及操作DOM,这决定了JS是单线程的,效率高;
    2. H5中的Web Workers可以多线程运行;
    3. 浏览器是多线程运行的,Firefox、老版IE是单进程,新版IE、Chrome是多进程;
    4. 浏览器内核:支撑浏览器运行的核心程序,由很多模块组成;
        1. Chrome/Safari:webkit   Firefox:Gecko   IE:Trident
        2. 360、搜狗等国内浏览器的内核:Trident+webkit
        3. 内核模块-主线程:JS引擎模块(JS的编译与运行),HTML文档解析模块,DOM/CSS模块
        (DOM/CSS在内存中的相关处理),布局和渲染模块(负责页面的布局和效果的绘制)...
        4. 内核模块-子线程:定时器模块(管理定时器),事件响应模块(管理事件),网络请求模块
        (AJAX请求)...
    

    JS是单线程

    1. 定时器机制:
        1. 定时器并不能保证真正的定时执行,一般会延迟一点点,但也有可能延迟很长时间;
        2. 定时器其实是在主线程中执行的,因为JS是单线程的,如果定时器执行前做耗时/阻塞的
        操作,那么就可能造成定时器延迟很长时间。
    2. JS代码分为初始化代码、回调代码,JS引擎执行代码的基本流程:
        1. 先执行初始化代码:包括设置定时器、绑定监听、发送AJAX请求
        2. 在后面的某个时刻才会执行回调代码;
        3. 弹出alert,JS代码是阻塞的,计时也会被暂停,定时器随之被延迟,直到关闭alert后
        才会恢复计时,执行定时器。
    3. 事件驱动模型
        1. event loop:事件轮询,事件包括定时器、DOM事件、AJAX
        2. callback queue:事件的回调队列,存放待处理的回调函数;
        3. 当事件发生时,管理模块会将回调函数及其数据添加到回调队列中,等待主线程执行。
    

    Web Workers

    1. JS是单线程的,在做耗时的操作时,如大量计算,Web界面就会卡死;
    2. Web Workers是H5提供的一个JS多线程解决方案,子线程完全受主线程控制,由子线程去执行
    耗时的计算,避免冻结主线程,但H5不允许子线程操作DOM,所以并没有改变JS单线程的本质;
    3. 使用Web Workers:
        1. 创建子线程执行的JS文件:worker.js
        var onmessage = function(event) {  --> 接收主线程发来的消息,var可省略
            var data = event.data
            postMessage('Hello Main') --> 向主线程发消息
        }
        2. 在主线程中的JS中发消息,并设置回调:
        var worker = new Worker('worker.js')
        worker.onmessage = function(event) { --> 监听子线程发来的消息
            var data = event.data --> 获取子线程发来的数据
        }
        worker.postMessage('Hello Worker'); --> 向子线程发送消息
    4. 主线程的全局上下文是window,而子线程的全局上下文DedicatedWorkerGlobalScope
        1. DedicatedWorkerGlobalScope的属性/方法:
        onmessage: null,postMessage: function,close: function ...
        2. 子线程的全局上下文对象中没有alert()、document等,所以子线程中不能更新界面。
    5. Web Workers的缺点:慢,不能跨域加载JS,不能操作DOM,有些浏览器不支持。
    

    自动化与优化

    1. less、sass、stylus:三种样式动态语言,属于CSS预处理语言,便于CSS的编写和维护;
        1. 有类似于CSS的语法,赋予CSS动态语言的特性,如变量、继承、函数等;
        2. 文件后缀分别是:x.less、x.scss、x.styl,并不能直接使用,需要编译成CSS文件;
        3. 编译方式:软件编译如koala,或者用nodejs程序编译,如grunt、gulp
    2. gulp比grunt更简洁、性能更高,gulp的常用插件:
        1. 压缩JS代码gulp-uglify、less的编译gulp-less、CSS的压缩gulp-minify-css.
        2. 自动添加CSS3前缀gulp-autoprefixer、文件重命名gulp-rename.
    

    性能优化

    1. 代码部署
        1. 代码的压缩与合并:去除空格、换行等,可利用gulp工具的插件完成;
        2. 图片、JS、CSS等静态资源存储在与主站不同的域名地址,避免在传输时携带cookie;
        3. 权衡DNS查找次数,使用不同域名会增加DNS查找;与上述相违背,权衡处理;
        4. 使用内容分发网络 CDN;使用GZIP压缩传输,压缩效率高;
        5. 为文件设置Last-Modified、Expires和Etag,即本地缓存数据;
        6. 避免不必要的重定向,在链接末尾手动加"/",如https://www.baidu.com/
    2. HTML:避免空的src和href,不要在HTML中缩放图片。
    3. CSS
        1. 精简CSS选择器的层级,并把CSS放到顶部,避免@import的方式引入样式;
        2. 使用Base64编码的图片数据取代图片文件,减少请求次数;
        3. 使用CSS动画来取代JS动画,CSS动画是虚拟完成的,并不会改变页面结构;
        4. 使用字体图标:https://fontawesome.com/icons
        5. 使用CSS Sprite雪碧图,SVG图像;避免使用CSS表达式和滤镜。
    4. JavaScript
        1. 减少引用库的个数,使用模块化概念的requerejs/seajs异步加载JS;
        2. JS在加载时会阻塞页面继续向下解析,理论上JS应该放在页面底部引用;
        3. 避免全局查找,约束范围去查找;减少属性查找;尽可能使用原生方法;
        4. 用switch代替复杂的if-else;减少语句数,比如多个变量声明可以合成一句;
        5. 使用字面量表达式来初始化数组/对象,比如arr=[1,2,3]取代new Array(1,2,3);
        6. 使用DocumentFragments/innerHTML取代复杂的元素注入;
        7. 使用事件代理/委托;高频触发的事件设置函数节流;
        8. 避免多次dom选择集,使用变量存储,var d = $('#div');
        9. 使用Web Storage缓存数据;使用Array的join()取代字符串的"+"连接。
  • 相关阅读:
    前缀和问题
    AtCoder Beginner Contest 085(ABCD)
    73.链表的基本操作
    112、文本串的加密
    100.容器List-ArrayList
    GUI颜色、字体设置对话框
    (贪心)多机调度问题
    POJ-1700 Crossing River
    lower_bound() upper_bound()函数
    HDU 1141
  • 原文地址:https://www.cnblogs.com/GME-qiyueliu/p/11452691.html
Copyright © 2020-2023  润新知