精华内容
下载资源
问答
  • js面试题

    千次阅读 多人点赞 2019-04-09 19:42:32
    JavaScript 的组成 JavaScript 由以下三部分组成: ECMAScript(核心):JavaScript 语言基础 ...BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法 JS 的基本数据类型和引用数据类型 ...

    JavaScript 的组成

    JavaScript 由以下三部分组成:

    • ECMAScript(核心):JavaScript 语言基础
    • DOM(文档对象模型):规定了访问 HTML 和 XML 的接口
    • BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法

    JS 的基本数据类型和引用数据类型

    • 基本数据类型:undefined、null、boolean、number、string、symbol
    • 引用数据类型:object、array、function

    检测浏览器版本版本有哪些方式?

    • 根据 navigator.userAgent // UA.toLowerCase().indexOf(‘chrome’)
    • 根据 window 对象的成员 // ‘ActiveXObject’ in window

    介绍 JS 有哪些内置对象?

    • 数据封装类对象:Object、Array、Boolean、Number、String
    • 其他对象:Function、Arguments、Math、Date、RegExp、Error
    • ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect

    说几条写 JavaScript 的基本规范?

    • 代码缩进,建议使用“四个空格”缩进
    • 代码段使用花括号{}包裹
    • 语句结束使用分号;
    • 变量和函数在使用前进行声明
    • 以大写字母开头命名构造函数,全大写命名常量
    • 规范定义 JSON 对象,补全双引号
    • 用{}和[]声明对象和数组

    如何编写高性能的 JavaScript?

    • 遵循严格模式:“use strict”;
    • 将 js 脚本放在页面底部,加快渲染页面
    • 将 js 脚本将脚本成组打包,减少请求
    • 使用非阻塞方式下载 js 脚本
    • 尽量使用局部变量来保存全局变量
    • 尽量减少使用闭包
    • 使用 window 对象属性方法时,省略 window
    • 尽量减少对象成员嵌套
    • 缓存 DOM 节点的访问
    • 通过避免使用 eval() 和 Function() 构造器
    • 给 setTimeout() 和 setInterval() 传递函数而不是字符串作为参数
    • 尽量使用直接量创建对象和数组
    • 最小化重绘(repaint)和回流(reflow)

    DOM 元素 e 的 e.getAttribute(propName)和 e.propName 有什么区别和联系

    • e.getAttribute(),是标准 DOM 操作文档元素属性的方法,具有通用性可在任意文档上使用,返回元素在源文件中设置的属性
    • e.propName 通常是在 HTML 文档中访问特定元素的特性,浏览器解析元素后生成对应对象(如 a 标签生成 HTMLAnchorElement),这些对象的特性会根据特定规则结合属性设置得到,对于没有对应特性的属性,只能使用 getAttribute 进行访问
    • e.getAttribute()返回值是源文件中设置的值,类型是字符串或者 null(有的实现返回"")
    • e.propName 返回值可能是字符串、布尔值、对象、undefined 等
    • 大部分 attribute 与 property 是一一对应关系,修改其中一个会影响另一个,如 id,title 等属性
    • 一些布尔属性<input hidden/>的检测设置需要 hasAttribute 和 removeAttribute 来完成,或者设置对应 property
    • <a href="../index.html">link</a>中 href 属性,转换成 property 的时候需要通过转换得到完整 URL
    • 一些 attribute 和 property 不是一一对应如:form 控件中<input value="hello"/>对应的是 defaultValue,修改或设置 value property 修改的是控件当前值,setAttribute 修改 value 属性不会改变 value property

    offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight 的区别

    • offsetWidth/offsetHeight 返回值包含 content + padding + border,效果与 e.getBoundingClientRect()相同
    • clientWidth/clientHeight 返回值只包含 content + padding,如果有滚动条,也不包含滚动条
    • scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸

    描述浏览器的渲染过程,DOM 树和渲染树的区别?

    浏览器的渲染过程:

    • 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
    • CSS 文件下载完成,开始构建 CSSOM(CSS 树)
    • CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
    • 布局(Layout):计算出每个节点在屏幕中的位置
    • 显示(Painting):通过显卡把页面画到屏幕上

    DOM 树 和 渲染树 的区别:

    • DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素
    • 渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性

    重绘和回流(重排)的区别和关系?

    • 重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘
    • 回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/状态状态)发生改变时,产生重绘回流
    • 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值
    • 回流必将引起重绘,而重绘不一定会引起回流

    如何最小化重绘(repaint)和回流(reflow)?

    • 需要要对元素进行复杂的操作时,可以先隐藏(display:“none”),操作完成后再显示
    • 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document
    • 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
    • 尽量避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)
    • 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)
    • 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color
      批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx

    script 的位置是否会影响首屏显示时间?

    • 在解析 HTML 生成 DOM 过程中,js 文件的下载是并行的,不需要 DOM 处理到 script 节点。因此,script 的位置不影响首屏显示的开始时间。
    • 浏览器解析 HTML 是自上而下的线性过程,script 作为 HTML 的一部分同样遵循这个原则
    • 因此,script 会延迟 DomContentLoad,只显示其上部分首屏内容,从而影响首屏显示的完成时间

    解释 JavaScript 中的作用域与变量声明提升?

    JavaScript 作用域:

    • 在 Java、C 等语言中,作用域为 for 语句、if 语句或{}内的一块区域,称为作用域;
    • 而在 JavaScript 中,作用域为 function(){}内的区域,称为函数作用域。

    JavaScript 变量声明提升:

    • 在 JavaScript 中,函数声明与变量声明经常被 JavaScript 引擎隐式地提升到当前作用域的顶部。
    • 声明语句中的赋值部分并不会被提升,只有名称被提升
    • 函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
    • 如果函数有多个同名参数,那么最后一个参数(即使没有定义)会覆盖前面的同名参数

    介绍 JavaScript 的原型,原型链?有什么特点?

    原型:

    • JavaScript 的所有对象中都包含了一个 [proto] 内部属性,这个属性所对应的就是该对象的原型
    • JavaScript 的函数对象,除了原型 [proto] 之外,还预置了 prototype 属性
    • 当函数对象作为构造函数创建实例时,该 prototype 属性值将被作为实例对象的原型 [proto]。

    原型链:

    • 当一个对象调用的属性/方法自身不存在时,就会去自己 [proto] 关联的前辈 prototype 对象上去找
    • 如果没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的“原型链”

    原型特点:

    • JavaScript 对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变

    JavaScript 有几种类型的值?,你能画一下他们的内存图吗

    • 原始数据类型(Undefined,Null,Boolean,Number、String)-- 栈
    • 引用数据类型(对象、数组和函数)-- 堆
    • 两种类型的区别是:存储位置不同:
    • 原始数据类型是直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据;
    • 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;
    • 引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。
    • 当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

    JavaScript 如何实现一个类,怎么实例化这个类?

    1. 构造函数法(this + prototype) – 用 new 关键字 生成实例对象
      • 缺点:用到了 this 和 prototype,编写复杂,可读性差
      function Mobile(name, price){
         this.name = name;
         this.price = price;
       }
       Mobile.prototype.sell = function(){
          alert(this.name + ",售价 $" + this.price);
       }
       var iPhone7 = new Mobile("iPhone7", 1000);
       iPhone7.sell();
    
    1. Object.create 法 – 用 Object.create() 生成实例对象
      • 缺点:不能实现私有属性和私有方法,实例对象之间也不能共享数据
     var Person = {
         firstname: "Mark",
         lastname: "Yun",
         age: 25,
         introduce: function(){
             alert('I am ' + Person.firstname + ' ' + Person.lastname);
         }
     };
    
     var person = Object.create(Person);
     person.introduce();
    
     // Object.create 要求 IE9+,低版本浏览器可以自行部署:
     if (!Object.create) {
        Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
      };
     }
    
    1. 极简主义法(消除 this 和 prototype) – 调用 createNew() 得到实例对象
      • 优点:容易理解,结构清晰优雅,符合传统的"面向对象编程"的构造
     var Cat = {
       age: 3, // 共享数据 -- 定义在类对象内,createNew() 外
       createNew: function () {
         var cat = {};
         // var cat = Animal.createNew(); // 继承 Animal 类
         cat.name = "小咪";
         var sound = "喵喵喵"; // 私有属性--定义在 createNew() 内,输出对象外
         cat.makeSound = function () {
           alert(sound);  // 暴露私有属性
         };
         cat.changeAge = function(num){
           Cat.age = num; // 修改共享数据
         };
         return cat; // 输出对象
       }
     };
    
     var cat = Cat.createNew();
     cat.makeSound();
    
    1. ES6 语法糖 class – 用 new 关键字 生成实例对象
         class Point {
           constructor(x, y) {
             this.x = x;
             this.y = y;
           }
           toString() {
             return '(' + this.x + ', ' + this.y + ')';
           }
         }
    
      var point = new Point(2, 3);
    

    Javascript 如何实现继承?

    1. 构造函数绑定:使用 call 或 apply 方法,将父对象的构造函数绑定在子对象上
    function Cat(name,color){
      Animal.apply(this, arguments);
      this.name = name;
      this.color = color;
    }
    
    1. 实例继承:将子对象的 prototype 指向父对象的一个实例
    Cat.prototype = new Animal();
    Cat.prototype.constructor = Cat;
    
    1. 拷贝继承:如果把父对象的所有属性和方法,拷贝进子对象
    function extend(Child, Parent) {
       var p = Parent.prototype;
       var c = Child.prototype;
       for (var i in p) {
          c[i] = p[i];
       }
       c.uber = p;
    }
    
    1. 原型继承:将子对象的 prototype 指向父对象的 prototype
    function extend(Child, Parent) {
        var F = function(){};
         F.prototype = Parent.prototype;
         Child.prototype = new F();
         Child.prototype.constructor = Child;
         Child.uber = Parent.prototype;
    }
    
    1. ES6 语法糖 extends:class ColorPoint extends Point {}
    class ColorPoint extends Point {
        constructor(x, y, color) {
            super(x, y); // 调用父类的constructor(x, y)
            this.color = color;
        }
        toString() {
            return this.color + ' ' + super.toString(); // 调用父类的toString()
        }
    }
    

    js 继承方式及其优缺点

    原型链继承的缺点

    • 一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

    借用构造函数(类式继承)

    • 借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承

    组合式继承

    • 组合式继承是比较常用的一种继承方法,其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。

    javascript 创建对象的几种方式?

    javascript 创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用 JSON;但写法有很多种,也能混合使用

    1. 对象字面量的方式
    person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
    
    1. 用 function 来模拟无参的构造函数
     function Person(){}
        var person=new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class
            person.name="Mark";
            person.age="25";
            person.work=function(){
            alert(person.name+" hello...");
        }
    person.work();
    
    1. 用 function 来模拟参构造函数来实现(用 this 关键字定义构造的上下文属性)
    function Pet(name,age,hobby){
        this.name=name;//this作用域:当前对象
        this.age=age;
        this.hobby=hobby;
        this.eat=function(){
            alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");
        }
    }
    var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象
    maidou.eat();//调用eat方法
    
    1. 用工厂方式来创建(内置对象)
    var wcDog =new Object();
         wcDog.name="旺财";
         wcDog.age=3;
    wcDog.work=function(){
        alert("我是"+wcDog.name+",汪汪汪......");
    }
    wcDog.work();
    
    1. 用原型方式来创建
    function Dog(){
    
        }
    Dog.prototype.name="旺财";
    Dog.prototype.eat=function(){
        alert(this.name+"是个吃货");
    }
    var wangcai =new Dog();
    wangcai.eat();
    
    1. 用混合方式来创建
    function Car(name,price){
        this.name=name;
        this.price=price;
    }
        Car.prototype.sell=function(){
        alert("我是"+this.name+",我现在卖"+this.price+"万元");
        }
    var camry =new Car("凯美瑞",27);
    camry.sell();
    

    Javascript 作用链域?

    • 全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节
    • 如果当前作用域没有找到属性或方法,会向上层作用域查找,直至全局函数,这种形式就是作用域链

    谈谈 this 对象的理解

    • this 总是指向函数的直接调用者
    • 如果有 new 关键字,this 指向 new 出来的实例对象
    • 在事件中,this 指向触发这个事件的对象
    • IE 下 attachEvent 中的 this 总是指向全局对象 Window

    eval 是做什么的?

    eval 的功能是把对应的字符串解析成 JS 代码并运行

    • 应该避免使用 eval,不安全,非常耗性能(先解析成 js 语句,再执行)
    • 由 JSON 字符串转换为 JSON 对象的时候可以用 eval(’(’+ str +’)’);

    什么是 Window 对象? 什么是 Document 对象?

    • Window 对象表示当前浏览器的窗口,是 JavaScript 的顶级对象。
    • 我们创建的所有对象、函数、变量都是 Window 对象的成员。
    • Window 对象的方法和属性是在全局范围内有效的。
    • Document 对象是 HTML 文档的根节点与所有其他节点(元素节点,文本节点,属性节点, 注释节点)
    • Document 对象使我们可以通过脚本对 HTML 页面中的所有元素进行访问
    • Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问

    介绍 DOM 的发展

    • DOM:文档对象模型(Document Object Model),定义了访问 HTML 和 XML 文档的标准,与编程语言及平台无关
    • DOM0:提供了查询和操作 Web 文档的内容 API。未形成标准,实现混乱。如:document.forms[‘login’]
    • DOM1:W3C 提出标准化的 DOM,简化了对文档中任意部分的访问和操作。如:JavaScript 中的 Document 对象
    • DOM2:原来 DOM 基础上扩充了鼠标事件等细分模块,增加了对 CSS 的支持。如:getComputedStyle(elem, pseudo)
    • DOM3:增加了 XPath 模块和加载与保存(Load and Save)模块。如:XPathEvaluator

    介绍 DOM0,DOM2,DOM3 事件处理方式区别

    DOM0 级事件处理方式:

    • btn.onclick = func;
    • btn.onclick = null;

    DOM2 级事件处理方式:

    • btn.addEventListener(‘click’, func, false);
    • btn.removeEventListener(‘click’, func, false);
    • btn.attachEvent(“onclick”, func);
    • btn.detachEvent(“onclick”, func);

    DOM3 级事件处理方式:

    • eventUtil.addListener(input, “textInput”, func);
    • eventUtil 是自定义对象,textInput 是 DOM3 级事件

    事件的三个阶段

    捕获、目标、冒泡

    介绍事件“捕获”和“冒泡”执行顺序和事件的执行次数?

    按照 W3C 标准的事件:首是进入捕获阶段,直到达到目标元素,再进入冒泡阶段

    事件执行次数(DOM2-addEventListener):元素上绑定事件的个数

    • 注意 1:前提是事件被确实触发
    • 注意 2:事件绑定几次就算几个事件,即使类型和功能完全一样也不会“覆盖”

    事件执行顺序:判断的关键是否目标元素

    • 非目标元素:根据 W3C 的标准执行:捕获->目标元素->冒泡(不依据事件绑定顺序)
    • 目标元素:依据事件绑定顺序:先绑定的事件先执行(不依据捕获冒泡标准)
    • 最终顺序:父元素捕获->目标元素事件 1->目标元素事件 2->子元素捕获->子元素冒泡->父元素冒泡
    • 注意:子元素事件执行前提 事件确实“落”到子元素布局区域上,而不是简单的具有嵌套关系

    在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次,先执行冒泡还是捕获?

    • 该 DOM 上的事件如果被触发,会执行两次(执行次数等于绑定次数)
    • 如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
    • 如果该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡

    事件的代理/委托

    事件委托是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件

    优点:

    • 可以减少事件注册,节省大量内存占用
    • 可以将事件应用于动态添加的子元素上

    缺点: 使用不当会造成事件在不应该触发时触发

    示例:

    ulEl.addEventListener('click', function(e){
        var target = event.target || event.srcElement;
        if(!!target && target.nodeName.toUpperCase() === "LI"){
            console.log(target.innerHTML);
        }
    }, false);
    

    IE 与火狐的事件机制有什么区别? 如何阻止冒泡?

    IE 只事件冒泡,不支持事件捕获;火狐同时支持件冒泡和事件捕获。

    阻止冒泡:

    • 取消默认操作: w3c 的方法是 e.preventDefault(),IE 则是使用 e.returnValue = false;
    • return false javascript 的 return false 只会阻止默认行为,而是用 jQuery 的话则既阻止默认行为又防止对象冒泡。
    • 阻止冒泡 w3c 的方法是 e.stopPropagation(),IE 则是使用 e.cancelBubble = true
    [js] view plaincopy
    function stopHandler(event)
    
        window.event?window.event.cancelBubble=true:event.stopPropagation();
    
    }
    

    参考链接:浅谈 javascript 事件取消和阻止冒泡-开源中国 2015

    IE 的事件处理和 W3C 的事件处理有哪些区别?(必考)

    绑定事件

    • W3C: targetEl.addEventListener(‘click’, handler, false);
    • IE: targetEl.attachEvent(‘onclick’, handler);

    删除事件

    • W3C: targetEl.removeEventListener(‘click’, handler, false);
    • IE: targetEl.detachEvent(event, handler);

    事件对象

    • W3C: var e = arguments.callee.caller.arguments[0]
    • IE: window.event

    事件目标

    • W3C: e.target
    • IE: window.event.srcElement

    阻止事件默认行为

    • W3C: e.preventDefault()
    • IE: window.event.returnValue = false’

    阻止事件传播

    • W3C: e.stopPropagation()
    • IE: window.event.cancelBubble = true

    W3C 事件的 target 与 currentTarget 的区别?

    • target 只会出现在事件流的目标阶段
    • currentTarget 可能出现在事件流的任何阶段
    • 当事件流处在目标阶段时,二者的指向相同
    • 当事件流处于捕获或冒泡阶段时:currentTarget 指向当前事件活动的对象(一般为父级)

    如何派发事件(dispatchEvent)?(如何进行事件广播?)

    • W3C: 使用 dispatchEvent 方法
    • IE: 使用 fireEvent 方法
    var fireEvent = function(element, event){
        if (document.createEventObject){
            var mockEvent = document.createEventObject();
            return element.fireEvent('on' + event, mockEvent)
        }else{
            var mockEvent = document.createEvent('HTMLEvents');
            mockEvent.initEvent(event, true, true);
            return !element.dispatchEvent(mockEvent);
        }
    }
    

    什么是函数节流?介绍一下应用场景和原理?

    • 函数节流(throttle)是指阻止一个函数在很短时间间隔内连续调用。 只有当上一次函数执行后达到规定的时间间隔,才能进行下一次调用。 但要保证一个累计最小调用间隔(否则拖拽类的节流都将无连续效果)
    • 函数节流用于 onresize, onscroll 等短时间内会多次触发的事件
    • 函数节流的原理:使用定时器做时间节流。 当触发一个事件时,先用 setTimout 让这个事件延迟一小段时间再执行。 如果在这个时间间隔内又触发了事件,就 clearTimeout 原来的定时器, 再 setTimeout 一个新的定时器重复以上流程。

    函数节流简单实现:

    function throttle(method, context) {
         clearTimeout(methor.tId);
         method.tId = setTimeout(function(){
             method.call(context);
         }100); // 两次调用至少间隔 100ms
    }
    // 调用
    window.onresize = function(){
        throttle(myFunc, window);
    }
    

    区分什么是“客户区坐标”、“页面坐标”、“屏幕坐标”?

    • 客户区坐标:鼠标指针在可视区中的水平坐标(clientX)和垂直坐标(clientY)
    • 页面坐标:鼠标指针在页面布局中的水平坐标(pageX)和垂直坐标(pageY)
    • 屏幕坐标:设备物理屏幕的水平坐标(screenX)和垂直坐标(screenY)

    如何获得一个 DOM 元素的绝对位置?

    • elem.offsetLeft:返回元素相对于其定位父级左侧的距离
    • elem.offsetTop:返回元素相对于其定位父级顶部的距离
    • elem.getBoundingClientRect():返回一个 DOMRect 对象,包含一组描述边框的只读属性,单位像素

    分析 [‘1’, ‘2’, ‘3’].map(parseInt) 答案是多少?(常考)

    答案:[1, NaN, NaN]

    parseInt(string, radix) 第 2 个参数 radix 表示进制。省略 radix 或 radix = 0,则数字将以十进制解析

    map 每次为 parseInt 传 3 个参数(elem, index, array),其中 index 为数组索引

    因此,map 遍历 [“1”, “2”, “3”],相应 parseInt 接收参数如下

    parseInt('1', 0);  // 1
    parseInt('2', 1);  // NaN
    parseInt('3', 2);  // NaN
    

    所以,parseInt 参数 radix 不合法,导致返回值为 NaN

    new 操作符具体干了什么?

    • 创建实例对象,this 变量引用该对象,同时还继承了构造函数的原型
    • 属性和方法被加入到 this 引用的对象中
    • 新创建的对象由 this 所引用,并且最后隐式的返回 this

    用原生 JavaScript 的实现过什么功能吗?

    封装选择器、调用第三方 API、设置和获取样式(自由回答)

    解释一下这段代码的意思吗?

      [].forEach.call($$("*"), function(el){
          el.style.outline = "1px solid #" + (~~(Math.random()*(1<<24))).toString(16);
      })
    

    解释:获取页面所有的元素,遍历这些元素,为它们添加 1 像素随机颜色的轮廓(outline)

    • ( s e l ) / / (sel) // (sel)//函数被许多现代浏览器命令行支持,等价于 document.querySelectorAll(sel)
    • [].forEach.call(NodeLists) // 使用 call 函数将数组遍历函数 forEach 应到节点元素列表
    • el.style.outline = “1px solid #333” // 样式 outline 位于盒模型之外,不影响元素布局位置
    • (1<<24) // parseInt(“ffffff”, 16) == 16777215 == 2^24 - 1 // 1<<24 == 2^24 == 16777216
    • Math.random()*(1<<24) // 表示一个位于 0 到 16777216 之间的随机浮点数
    • ~~Math.random()*(1<<24) // ~~ 作用相当于 parseInt 取整
    • (~~(Math.random()*(1<<24))).toString(16) // 转换为一个十六进制-

    JavaScript 实现异步编程的方法?

    • 回调函数
    • 事件监听
    • 发布/订阅
    • Promises 对象
    • Async 函数[ES7]

    web 开发中会话跟踪的方法有哪些

    • cookie
    • session
    • url 重写
    • 隐藏 input
    • ip 地址

    什么是闭包(closure),为什么要用它?

    闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域

    闭包的特性:

    • 函数内再嵌套函数
    • 内部函数可以引用外层的参数和变量
    • 参数和变量不会被垃圾回收机制回收

    javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?

    use strict 是一种 ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行,使 JS 编码更加规范化的模式,消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为

    如何判断一个对象是否属于某个类?

    // 使用instanceof (待完善)
       if(a instanceof Person){
           alert('yes');
       }
    

    js 延迟加载的方式有哪些?

    defer 和 async、动态创建 DOM 方式(用得最多)、按需异步载入 js

    defer 和 async

    defer 并行加载 js 文件,会按照页面上 script 标签的顺序执行 async 并行加载 js 文件,下载完成立即执行,不会按照页面上 script 标签的顺序执行

    Ajax 是什么? 如何创建一个 Ajax?

    ajax 的全称:Asynchronous Javascript And XML

    异步传输+js+xml

    所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验

    • 创建 XMLHttpRequest 对象,也就是创建一个异步调用对象
    • 建一个新的 HTTP 请求,并指定该 HTTP 请求的方法、URL 及验证信息
    • 设置响应 HTTP 请求状态变化的函数
    • 发送 HTTP 请求
    • 获取异步调用返回的数据
    • 用 JavaScript 和 DOM 实现局部刷新

    同步和异步的区别?

    • 同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作
    • 异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容

    documen.write 和 innerHTML 的区别

    • document.write 只能重绘整个页面
    • innerHTML 可以重绘页面的一部分

    DOM 操作——怎样添加、移除、移动、复制、创建和查找节点?

    创建新节点

    • createDocumentFragment() //创建一个 DOM 片段
    • createElement() //创建一个具体的元素
    • createTextNode() //创建一个文本节点

    添加、移除、替换、插入

    • appendChild()
    • removeChild()
    • replaceChild()
    • insertBefore() //在已有的子节点前插入一个新的子节点

    查找

    • getElementsByTagName() //通过标签名称
    • getElementsByName() // 通过元素的 Name 属性的值(IE 容错能力较强,会得到一个数组,其中包括 id 等于 name 值的) * getElementById() //通过元素 Id,唯一性

    那些操作会造成内存泄漏?

    • 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
    • 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收
    • setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
    • 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

    渐进增强和优雅降级

    • 渐进增强 :针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
    • 优雅降级 :一开始就构建完整的功能,然后再针对低版本浏览器进行兼容

    Javascript 垃圾回收方法

    标记清除(mark and sweep)

    • 这是 JavaScript 最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
    • 垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了

    引用计数(reference counting)

    • 在低版本 IE 中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加 1,如果该变量的值变成了另外一个,则这个值得引用次数减 1,当这个值的引用次数变为 0 的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为 0 的值占用的空间

    参考链接 内存管理-MDN

    用过哪些设计模式?

    1. 工厂模式:
    • 主要好处就是可以消除对象间的耦合,通过使用工程方法而不是 new 关键字。将所有实例化的代码集中在一个位置防止代码重复
    • 工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法 搞清楚他们到底是哪个对象的实例
    function createObject(name,age,profession){
        //集中实例化的函数
        var obj = new Object();
        obj.name = name;
        obj.age = age;
        obj.profession = profession;
        obj.move = function () {
            return this.name + ' at ' + this.age + ' engaged in ' + this.profession;
        };
        return obj;
    }
    var test1 = createObject('trigkit4',22,'programmer');//第一个实例var test2 = createObject('mike',25,'engineer');//第二个实例
    
    1. 构造函数模式
    • 使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于
    • 构造函数方法没有显示的创建对象 (new Object());
    • 直接将属性和方法赋值给 this 对象;
    • 没有 renturn 语句

    说说你对闭包的理解

    使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在 js 中,函数即闭包,只有函数才会产生作用域的概念

    闭包有三个特性:

    • 函数嵌套函数
    • 函数内部可以引用外部的参数和变量
    • 参数和变量不会被垃圾回收机制回收

    请解释一下 JavaScript 的同源策略

    • 概念:同源策略是客户端脚本(尤其是 Javascript)的重要的安全度量标准。它最早出自 Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议
    • 指一段脚本只能读取来自同一来源的窗口和文档的属性

    为什么要有同源限制?

    我们举例说明:比如一个黑客程序,他利用 Iframe 把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过 Javascript 读取到你的表单中 input 中的内容,这样用户名,密码就轻松到手了。]

    缺点: 现在网站的 JS 都会进行压缩,一些文件用了严格模式,而另一些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节

    实现一个函数 clone,可以对 JavaScript 中的 5 种主要的数据类型(包括 Number、String、Object、Array、Boolean)进行值复制(常考)

    function deepClone(obj) {
        if (!isObject(obj)) {
            throw new Error('obj 不是一个对象!')
        }
    
        let isArray = Array.isArray(obj)
        let cloneObj = isArray ? [] : {}
        for (let key in obj) {
            cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
        }
    
        return cloneObj
    }
    

    注意:for…in 法不支持拷贝 func、date、reg 和 err

    // 代理法
    function deepClone(obj) {
        if (!isObject(obj)) {
            throw new Error('obj 不是一个对象!')
        }
    
        let isArray = Array.isArray(obj)
        let cloneObj = isArray ? [...obj] : { ...obj }
        Reflect.ownKeys(cloneObj).forEach(key => {
            cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
        })
    
        return cloneObj
    }
    

    说说严格模式的限制

    • 严格模式主要有以下限制:
    • 变量必须声明后再使用
    • 函数的参数不能有同名属性,否则报错
    • 不能使用 with 语句
    • 不能对只读属性赋值,否则报错
    • 不能使用前缀 0 表示八进制数,否则报错
    • 不能删除不可删除的属性,否则报错
    • 不能删除变量 delete prop,会报错,只能删除属性 delete global[prop]
    • eval 不会在它的外层作用域引入变量
    • eval 和 arguments 不能被重新赋值
    • arguments 不会自动反映函数参数的变化
    • 不能使用 arguments.callee
    • 不能使用 arguments.caller
    • 禁止 this 指向全局对象
    • 不能使用 fn.caller 和 fn.arguments 获取函数调用的堆栈
    • 增加了保留字(比如 protected、static 和 interface)

    如何删除一个 cookie

    将时间设为当前时间往前一点

    var date = new Date();
    date.setDate(date.getDate() - 1);//真正的删除
    

    setDate()方法用于设置一个月的某一天

    expires 的设置

      document.cookie = 'user='+ encodeURIComponent('name')  + ';expires = ' + new Date(0)
    

    编写一个方法 求一个字符串的字节长度

    假设:一个英文字符占用一个字节,一个中文字符占用两个字节

    function GetBytes(str){
    
            var len = str.length;
    
            var bytes = len;
    
            for(var i=0; i<len; i++){
    
                if (str.charCodeAt(i) > 255) bytes++;
    
            }
    
            return bytes;
    
        }
    
    alert(GetBytes("你好,as"));
    

    请解释什么是事件代理

    事件代理(Event Delegation),又称之为事件委托。是 JavaScript 中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定的事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是 DOM 元素的事件冒泡。使用事件代理的好处是可以提高性能

    attribute 和 property 的区别是什么?

    • attribute 是 dom 元素在文档中作为 html 标签拥有的属性;
    • property 就是 dom 元素在 js 中作为对象拥有的属性。
    • 对于 html 的标准属性来说,attribute 和 property 是同步的,是会自动更新的
    • 但是对于自定义的属性来说,他们是不同步的

    页面编码和被请求的资源编码如果不一致如何处理?

    • 后端响应头设置 charset
    • 前端页面<meta>设置 charset

    <script> 放在 </body> 之前和之后有什么区别?浏览器会如何解析它们?

    按照 HTML 标准,在结束后出现<script>或任何元素的开始标签,都是解析错误
    虽然不符合 HTML 标准,但浏览器会自动容错,使实际效果与写在</body>之前没有区别
    浏览器的容错机制会忽略<script>之前的,视作<script>仍在 body 体内。省略</body></html>闭合标签符合 HTML 标准,服务器可以利用这一标准

    <script> 放在 </head> 中会有什么问题?

    在浏览器渲染页面之前,它需要通过解析HTML标记然后构建DOM树。在这个过程中,如果解析器遇到了一个脚本(script),它就会停下来,并且执行这个脚本,然后才会继续解析HTML。如果遇到了一个引用外部资源的脚本(script),它就必须停下来等待这个脚本资源的下载,而这个行为会导致一个或者多个的网络往返,并且会延迟页面的首次渲染时间。

    还有一点是需要我们注意的,那就是外部引入的脚本(script)会阻塞浏览器的并行下载,HTTP/1.1规范表明,浏览器在每个主机下并行下载的组件不超过两个(也就是说,浏览器一次只能够同时从同一个服务器加载两个脚本);如果你网站的图片是通过多个服务器提供的,那么按道理来说,你的网站可以一次并行下载多张图片。但是,当我们网站在加载脚本的时候;浏览器不会再启动任何其它的下载,即使这些组件来自不同的服务器。

    异步加载 JS 的方式有哪些?

    • 设置<script>属性 async=“async” (一旦脚本可用,则会异步执行)
    • 动态创建 script DOM:document.createElement(‘script’);
    • XmlHttpRequest 脚本注入
    • 异步加载库 LABjs
    • 模块加载器 Sea.js

    JavaScript 中,调用函数有哪几种方式?

    • 方法调用模式 Foo.foo(arg1, arg2);
    • 函数调用模式 foo(arg1, arg2);
    • 构造器调用模式 (new Foo())(arg1, arg2);
    • call/applay 调用模式 Foo.foo.call(that, arg1, arg2);
    • bind 调用模式 Foo.foo.bind(that)(arg1, arg2)();

    简单实现 Function.bind 函数?

      if (!Function.prototype.bind) {
        Function.prototype.bind = function(that) {
          var func = this, args = arguments;
          return function() {
            return func.apply(that, Array.prototype.slice.call(args, 1));
          }
        }
      }
      // 只支持 bind 阶段的默认参数:
      func.bind(that, arg1, arg2)();
    
      // 不支持以下调用阶段传入的参数:
      func.bind(that)(arg1, arg2);
    

    列举一下 JavaScript 数组和对象有哪些原生方法

    • 数组:
      • arr.concat(arr1, arr2, arrn);
      • arr.join(",");
      • arr.sort(func);
      • arr.pop();
      • arr.push(e1, e2, en);
      • arr.shift();
      • unshift(e1, e2, en);
      • arr.reverse();
      • arr.slice(start, end);
      • arr.splice(index, count, e1, e2, en);
      • arr.indexOf(el);
      • arr.includes(el); // ES6
    • 对象:
      • object.hasOwnProperty(prop);
      • object.propertyIsEnumerable(prop);
      • object.valueOf();
      • object.toString();
      • object.toLocaleString();
      • Class.prototype.isPropertyOf(object);

    Array.slice() 与 Array.splice() 的区别?

    • slice – “读取”数组指定的元素,不会对原数组进行修改

      • 语法:arr.slice(start, end)
      • start 指定选取开始位置(含)
      • end 指定选取结束位置(不含)
    • splice

      • “操作”数组指定的元素,会修改原数组,返回被删除的元素
      • 语法:arr.splice(index, count, [insert Elements])
      • index 是操作的起始位置
      • count = 0 插入元素,count > 0 删除元素
      • [insert Elements] 向数组新插入的元素

    JavaScript 对象生命周期的理解?

    • 当创建一个对象时,JavaScript 会自动为该对象分配适当的内存
    • 垃圾回收器定期扫描对象,并计算引用了该对象的其他对象的数量
    • 如果被引用数量为 0,或惟一引用是循环的,那么该对象的内存即可回收

    哪些操作会造成内存泄漏?

    • JavaScript 内存泄露指对象在不需要使用它时仍然存在,导致占用的内存不能使用或回收
    • 未使用 var 声明的全局变量
    • 闭包函数(Closures)
    • 循环引用(两个对象相互引用)
    • 控制台日志(console.log)
    • 移除存在绑定事件的 DOM 元素(IE)

    在 javascript 中,1 与 Number(1)有什么区别 [易混淆]

    var a = Number(1) // 1
    var b = new Number(1)  // Number {[[PrimitiveValue]]: 1}
    typeof (a) // number
    typeof (b) // object
    a == b // true
    
    • var a = 1 是一个常量,而 Number(1)是一个函数
    • new Number(1)返回的是一个对象
    • a==b 为 true 是因为所以在求值过程中,总是会强制转为原始数据类型而非对象,例如下面的代码:
    typeof 123 // "number"
    typeof new Number(123) // "object"
    123 instanceof Number // false
    (new Number(123)) instanceof Number // true
    123 === new Number(123) // false
    

    参考地址:面试题:在 javascript 中,1 与 Number(1)有什么区别

    console.log(!!(new Boolean(false))输出什么 [易混淆]

    true

    布尔的包装对象 Boolean 的对象实例,对象只有在 null 与 undefined 时,才会认定为布尔的 false 值,布尔包装对象本身是个对象,对象->布尔 都是 true,所以 new Boolean(false)其实是布尔的 true,看下面这段代码:

    if(new Boolean(false)){
        alert('true!!');
    }
    

    只有使用了 valueOf 后才是真正的转换布尔值,与上面包装对象与原始资料转换说明的相同:

    !!(new Boolean(false))  //true
    (new Boolean(false)).valueOf() //false
    

    为什么 JS 是单线程,而不是多线程 [常考]

    • 单线程是指 JavaScript 在执行的时候,有且只有一个主线程来处理所有的任务。
    • 目的是为了实现与浏览器交互。
    • 我们设想一下,如果 JavaScript 是多线程的,现在我们在浏览器中同时操作一个 DOM,一个线程要求浏览器在这个 DOM 中添加节点,而另一个线程却要求浏览器删掉这个 DOM 节点,那这个时候浏览器就会很郁闷,他不知道应该以哪个线程为准。所以为了避免此类现象的发生,降低复杂度,JavaScript 选择只用一个主线程来执行代码,以此来保证程序执行的一致性。

    浏览器中的 Event Loop

    浏览器中的Eventloop

    • 主线程运行的时候会生成堆(heap)和栈(stack);
    • js 从上到下解析方法,将其中的同步任务按照执行顺序排列到执行栈中;
    • 当程序调用外部的 API 时,比如 ajax、setTimeout 等,会将此类异步任务挂起,继续执行执行栈中的任务,等异步任务返回结果后,再按照执行顺序排列到事件队列中;
    • 主线程先将执行栈中的同步任务清空,然后检查事件队列中是否有任务,如果有,就将第一个事件对应的回调推到执行栈中执行,若在执行过程中遇到异步任务,则继续将这个异步任务排列到事件队列中。
    • 主线程每次将执行栈清空后,就去事件队列中检查是否有任务,如果有,就每次取出一个推到执行栈中执行,这个过程是循环往复的… …,这个过程被称为“Event Loop 事件循环”

    参考地址:Event Loop 这个循环你晓得么?(附 GIF 详解)-饿了么前端

    展开全文
  • SPSS(十九)SPSS之时间序列模型(图文+数据集)

    万次阅读 多人点赞 2019-06-17 22:32:38
    它考虑的不是变量间的因果关系,而是重点考察变量在时间方面的发展变化规律,并为之建立数学模型 使用时间序列模型的前提:有足够长的数据序列;数据序列的变动是稳定而规律的 另外一种理解方式:假如我们对一...

    SPSS(十九)SPSS之时间序列模型(图文+数据集)

    时间序列是指将同一统计指标的数值按其发生的时间先后顺序排列而成的数列。正如人们常说,人生的出场顺序很重要,时间序列中隐藏着一些过去与未来的关系。时间序列分析试图通过研究过去来预测未来。

    时间序列分析在工程、金融、科技等众多领域有着广泛的应用。在大数据时代,时间序列分析已经成为 AI 技术的一个分支,通过将时间序列分析与分类模型相结合,更好的应用于数据检测、预测等场景。

    时间序列模型简介

    • 依时间顺序排列起来的一系列观测值(观测值之间不独立)
    • 它考虑的不是变量间的因果关系,而是重点考察变量在时间方面的发展变化规律,并为之建立数学模型
    • 使用时间序列模型的前提:有足够长的数据序列;数据序列的变动是稳定而规律的

    另外一种理解方式:假如我们对一件事情研究其背后规律很久的话,可以收集到很多的自变量/影响因素去研究与因变量之间的关系,但是由于各种原因我们做不到,我们只能用一个t(时间)来替代所有的影响因素来研究自变量是如何变化的

     

    时间序列分析面临的问题

    时序应该在现实生活中应用的很广,但是为什么不常用这个模型呢?

    • 基础统计数据原因(数据收集)

    报表系统——质量问题
    统计口径——不统一
    范围变化、区域划分——变化

    • 理论和技术培训原因 

    之前没有好的工具来实现时间序列模型

     

    时间序列的方法分类

    • Time domain(最为常见的方法):将时间序列看成是过去一些点的函数,或者认为序列具有随时间系统变化的趋势,它可以用不多的参数来加以描述,或者说可以通过差分、周期等还原成随机序列。
    • Frequency domain:认为时间序列是由数个正弦波成份叠加而成,当序列的确来自一些周期函数集合时,该方法特别有用。 比如心电图
       

    时间序列的构成

    并不是每个序列都包含所有4种成分。比如以年为时间单位的序列就不会有季节变化;
    一些较短的序列也看不出循环变化。所以在分析的时候得具体情况具体分析。 

    • 长期趋势

    指一种长期的变化趋势。它采取一种全局的视角,不考虑序列局部的波动

    下图,整体呈下降趋势

    • 季节变化(Season)

    反映一种周期性的变化一般在一年中完成
    虽然称作“季节”,但是周期并不一定是季度,也可以是月、周等其它能在一年内完成的周期。因为,大多数的周期都以季节的形式出现,所以称作季节变化

    比较典型的季节变化例子:圣诞节效应;冷饮的销售情况

    • 循环变化(Cyclic)

    循环跨度超年

    指一种较长时间的周期变化。一般来说循环时间为2-15年。循环变化一般会出现波峰和波谷,呈现一种循环往复的现象。 
    比如:经济危机 

    • 不规则变化(error) 

    指时间序列中无法预计的部分,也可以理解为误差
    序列的随机波动 
    突发事件引起的 
    它是无法预测的 
    在分析中往往又将其称为白噪声

    它是时间序列中除去趋势、季节变化和自相关性之后的剩余随机扰动。由于时间序列存在不确定性,随机噪声总是夹杂在时间序列中,致使时间序列表现出某种震荡式的无规律运动。
    比如:911事件

     

    时间序列分析对长度的要求

    • 不同的序列分析方法对时间序列分析对长度不一样,建模过程一般都会做差分,差分会损失信息,差分得越多,相应要求的时间序列越长
    • 如果是稳定序列的话,历史数据越多,对预测的帮助越大
    • 如果存在周期,一般需要4个周期以上数理上认为应当在20个周期以上

           假如只有两三个周期,那周期性的分析就没有太大作用了

     

    对于时间序列问题有哪些基本分析思路

    看到数据其实不一定要上最复杂的方法

    • 平滑与季节分解(遇到比较简单的序列)

    用移动平均的方式消除波动,反映出主要的趋势

    • 回归模型

    如果在序列分析中我们考虑到自变量的话,根据历史数据建立相应的回归模型用于预测。甚至来说可以直接把时间当做自变量用于预测,当然我们知道回归时候要求残差是独立的,假如检验出来是非独立的话,我们可以去建一个自回归模型

    • ARIMA

    如果时间序列变化太复杂,我们可以采用ARIMA建模,现在最强大的时序建模方法。真正的时间序列模型建模分析方法
     

    平滑与季节分解

    • 是利用时间序列资料进行短期预测的一种方法。它的基本思想是:除去一些不规则变化后,时间序列将剩下一些基本的变化模式,而这种变化模式将延续到将来。
    • 描述时间序列数据的变化规律和行为,不去试图解释和理解这种变化的原因。例如:您可能发现在过去的一年里,三月和九月都会出现销售的高峰,您可能希望继续保持这样,尽管您不知道为什么。
    • 平滑的主要目的就是除去时间序列的不规则变化,把时间序列的基本变化模式突现出来,作为短期预测的基础。因此也有人把平滑称作“修匀”。
    • 平滑的方法很多。广义上说,可以认为回归也是一种平滑。因为拟合回归曲线可以把杂乱的观测数据修匀得到连续而光滑的曲线。
    • 移动平均和移动中位数等这些不同的平滑技术又被称为平滑器。平滑处理后,可以得到一些新的序列。不同的平滑器得到的新序列是不同的。选择合适的平滑器,寻求最佳的预测效果是平滑处理的关键。

     

    案例:NRC数据的建模预测

    美国1947年1月到1969年12月住宅建筑的数据,分析目的是希望能过通过历史数据来预测1970年全年的情况。

    数据集

    nrc是我们准备用于分析的变量

    nrc2又新增了12个月的数据,可以用来评价我们的预测效果

    556	556
    528	528
    545	545
    607	607
    701	701
    785	785
    874	874
    950	950
    1006	1006
    1093	1093
    1135	1135
    1070	1070
    891	891
    757	757
    874	874
    1028	1028
    1168	1168
    1257	1257
    1294	1294
    1305	1305
    1273	1273
    1203	1203
    1100	1100
    978	978
    846	846
    731	731
    763	763
    844	844
    981	981
    1086	1086
    1147	1147
    1171	1171
    1207	1207
    1238	1238
    1241	1241
    1171	1171
    1077	1077
    1031	1031
    1089	1089
    1276	1276
    1499	1499
    1703	1703
    1827	1827
    1898	1898
    1900	1900
    1785	1785
    1614	1614
    1427	1427
    1289	1289
    1188	1188
    1229	1229
    1288	1288
    1324	1324
    1399	1399
    1428	1428
    1409	1409
    1400	1400
    1397	1397
    1330	1330
    1200	1200
    1015	1015
    963	963
    1149	1149
    1234	1234
    1346	1346
    1437	1437
    1472	1472
    1486	1486
    1473	1473
    1481	1481
    1438	1438
    1309	1309
    1131	1131
    1057	1057
    1206	1206
    1363	1363
    1431	1431
    1570	1570
    1577	1577
    1550	1550
    1514	1514
    1481	1481
    1420	1420
    1294	1294
    1104	1104
    1029	1029
    1167	1167
    1347	1347
    1517	1517
    1627	1627
    1717	1717
    1770	1770
    1783	1783
    1759	1759
    1717	1717
    1650	1650
    1473	1473
    1379	1379
    1562	1562
    1753	1753
    1925	1925
    2064	2064
    2098	2098
    2082	2082
    2051	2051
    1983	1983
    1851	1851
    1656	1656
    1392	1392
    1305	1305
    1457	1457
    1618	1618
    1753	1753
    1884	1884
    1908	1908
    1895	1895
    1860	1860
    1798	1798
    1741	1741
    1567	1567
    1324	1324
    1206	1206
    1350	1350
    1486	1486
    1604	1604
    1718	1718
    1767	1767
    1796	1796
    1787	1787
    1761	1761
    1694	1694
    1513	1513
    1292	1292
    1192	1192
    1302	1302
    1421	1421
    1550	1550
    1702	1702
    1804	1804
    1876	1876
    1907	1907
    1954	1954
    1957	1957
    1832	1832
    1606	1606
    1493	1493
    1676	1676
    1907	1907
    2091	2091
    2253	2253
    2350	2350
    2358	2358
    2310	2310
    2232	2232
    2092	2092
    1883	1883
    1588	1588
    1408	1408
    1613	1613
    1804	1804
    1935	1935
    2112	2112
    2039	2039
    1982	1982
    1931	1931
    1860	1860
    1790	1790
    1644	1644
    1378	1378
    1221	1221
    1459	1459
    1720	1720
    1860	1860
    2059	2059
    2053	2053
    2053	2053
    2055	2055
    2041	2041
    1974	1974
    1807	1807
    1543	1543
    1368	1368
    1605	1605
    1906	1906
    2141	2141
    2377	2377
    2357	2357
    2377	2377
    2330	2330
    2210	2210
    2113	2113
    1965	1965
    1686	1686
    1492	1492
    1666	1666
    1950	1950
    2206	2206
    2421	2421
    2517	2517
    2553	2553
    2516	2516
    2500	2500
    2450	2450
    2230	2230
    1867	1867
    1678	1678
    1866	1866
    2068	2068
    2191	2191
    2385	2385
    2518	2518
    2541	2541
    2439	2439
    2327	2327
    2260	2260
    2118	2118
    1834	1834
    1639	1639
    1782	1782
    2000	2000
    2203	2203
    2429	2429
    2550	2550
    2561	2561
    2473	2473
    2377	2377
    2284	2284
    2136	2136
    1848	1848
    1644	1644
    1781	1781
    1979	1979
    2124	2124
    2287	2287
    2387	2387
    2351	2351
    2202	2202
    1978	1978
    1785	1785
    1614	1614
    1368	1368
    1248	1248
    1405	1405
    1613	1613
    1836	1836
    2107	2107
    2336	2336
    2471	2471
    2446	2446
    2375	2375
    2310	2310
    2191	2191
    1859	1859
    1655	1655
    1885	1885
    2262	2262
    2518	2518
    2628	2628
    2721	2721
    2790	2790
    2780	2780
    2678	2678
    2593	2593
    2454	2454
    2133	2133
    1940	1940
    2195	2195
    2540	2540
    2810	2810
    2962	2962
    2974	2974
    2880	2880
    2763	2763
    2648	2648
    2482	2482
    2288	2288
    	1961
    	1765
    	1986
    	2297
    	2485
    	2592
    	2650
    	2707
    	2721
    	2747
    	2735
    	2627


    时间序列操作的基本步骤

    • 预处理过程

    缺失值的填补 

    一般这两种方法我们比较常用


    时间变量的定义(spss对数据集进行了特殊标记,让spss知道其为序列数据,并非新增三个变量那么简单,必须是刚才进行下面的操作)


    时间序列的平稳化

    观测原始序列是什么分布,时间刻度这一块随便选一个时间自变量

    发现其有长期趋势及季节变化(大概一年)


    一次差分(假如序列匀速上升的话,一次差分序列后应该是平的)

    继续查看其变化(一次差分作为变量)

    确实序列变平了,但是随着时间增加季节变换还是存在的


    季节差分(把周期性也干掉),一阶:相邻的两个季节做相减

    看季节差分分布分布状况

    看到下面的序列,无长期趋势、无季节变换,可认为是一个比较平稳的序列了

    但是刚才上面在做一次差分后的序列,可以看出其序列随着时间增长离散程度会慢慢变大,后续分析可以考虑这一点,可以做变量变换。

    其实刚才上面的步骤不用那么麻烦,在序列图中即可观察

    当前周期:12在哪里设置呢?(在我们刚才定义日期选取的)

     

    关于数据平稳化问题:(非常详细的理论基础)

    大家可以参考

    https://zhuanlan.zhihu.com/p/60023855

    https://zhuanlan.zhihu.com/p/60648709

     

    时间序列趋势的图形化观察

    • Sequence Chart:序列图

    实际上就是一种特殊的线图

    • Autocorrelation Chart:做单个序列,任意滞后(包括负的滞后,也就是超前)的自相关和偏相关图

    对序列图的初步观察结果作进一步确认(检验其是不是白噪声序列)
    重点关心主要的相关趋势,然后再对模型进一步修正

    刚才我们认为做了一次差分和季节差分真的为平稳序列了吗?

    滞后n阶:隔了n个数据的自相关性

    Sig.<0.05,证明存在自相关的,不都是白噪声

    为了方便查看,给出了图,1到5阶都是存在统计学意义的

    自相关系数是有传递性的问题在里面的,spss就会计算偏自相关系数,屏蔽传递的效应后,看剩余的关联是否还存在

    自相关拖尾,偏自相关也拖尾,这两个是为了知道我们进行建模的

    自相关图:自回归系数的变化
    偏相关图:偏回归系数的变化

    假如他是以下模型,应满足下面的特征

    实际用起来,spss会提供一个自动分析的方法

    模型拟合
    几乎均可包含在ARIMA模型族中
    寻找适当的参数是一个反复尝试的过程

    生成 ARIMA 模型的基本步骤:

    1. 对序列绘图,进行 ADF 检验,观察序列是否平稳;对于非平稳时间序列要先进行 d 阶差分,转化为平稳时间序列;
    2. 经过第一步处理,已经得到平稳时间序列。要对平稳时间序列分别求得其自相关系数(ACF)和偏自相关系数(PACF),通过对自相关图和偏自相关图的分析,得到最佳的阶数p、q;
    3. 由以上得到的d、q、p ,得到 ARIMA 模型。然后开始对得到的模型进行模型检验。

    专家建模器:会在指数平滑模型和ARIMA模型里面选取

     

    R方相对于平稳的R方来说,是比较过于乐观的,假如数据是有波动趋势的,我们将趋势解释掉之后,占相当大的变异解释度进去了,平稳的R方比较客观

    RMSE(残差均方)

    MAPE(相对误差)

    MAXAPE(最大值相对误差)

    MAE(绝对误差)

    MAXAE(最大值绝对误差)

    正态化BIC(比较专业化的指标)

     

    当前模型剩下来的这块能否当成白噪声?

    H0:白噪声序列

    Sig.>0.05,剩下来的确实是白噪声序列

     

     

    如何让其做预测?怎么用时间序列?

    由于SPSS的一个小BUG,变量名前缀要修改一下,不能是中文

    对比一下原始序列和预测值效果

    我们想预测到久一点呢?

    假如我们有1970年的真实数据了,对比一下模型预测及真实数据差别

    展开全文
  • 把自己的理论应用于实践,观察实际效果,对比之前的预期,再领悟新的经验和思考,循环往复,就形成了方法论。 以上就是本文的全部内容了,与君共勉。 微.信.搜.一.搜.程序之心,每周一三五原创更新。

    作者:丁仪

    来源:https://chengxuzhixin.com/blog/post/30_sui_hou_de_fa_zhan_fang_xiang_he_tu_po.html

     

    前些年,有人说程序员只能干到 30,后来大家把年龄提到 35,最近好像又有提到 40 的迹象。最近 Python 创始人 Guido 入职微软了。Guido 在 1989 年创造了 Python,无论从哪个角度看,都是绝对的高龄程序员了。

     

    程序员是青春饭吗

    很多人都说写代码最多到 35 岁,妥妥的青春饭,然而科学分析不这么认为。《Is Programming Knowledge Related to Age?》论文对 1694981 名 StackOverflow 用户的研究发现,程序员的平均年龄是 30.3 岁,其中数据清洗后参与分析的用户是 84248 名程序员,平均年龄 29.02 岁。

    在年龄分布中,人数最多的是 25 岁,中位数是 29 岁。然而分析发现,程序员的能力从 25 岁左右开始上升,一直到 50 岁后才会开始下降。论文还研究了程序员对新技术的跟进,发现不同年龄的程序员对新技术的学习并没有差太多。大龄程序员对某些新技术的学习甚至超过年轻程序员。所以论文得出的结论是,程序员的技术能力上升可以到 50 - 60 岁,并且大龄程序员跟进新技术的能力和年轻程序员相差不多。

    从身边的观察发现,30 岁的程序员积累了大量经验,可能才刚刚成为优秀的人才,架构设计能力、领导力需要大量的实践积累,不是能够轻松掌握的。互联网是一个新兴行业,大部分从业者都是后期加入的,平均年龄要低于其他行业。

     

    30 岁后的职业规划

    一个程序员在 30 岁后,可能面临技术专家、技术 Leader、架构师三个发展方向的选择。

    技术专家很好理解,在一个领域深耕,对业务和代码都有很好深刻的理解,经验丰富,能够用技术解决公司遇到的实际问题。成为技术专家需要大量的实践积累,正常发展情况下差不多都要到 30 岁左右。正常来说,技术专家是人才梯队中非常重要的角色,对技术方案设计有很大影响。

    前几天看到有个公众号转载一篇高并发的文章,一个看起来一年内工作经验的作者展示了漏洞百出的技术方案,还能发上线,可见技术专家对团队的重要作用。没有技术专家的团队,人才梯队很难建立起来,团队内成员的成长可能也会受影响。

    技术 Leader 会开始涉及技术管理方面的事务。注意这里是 Leader,不是 Manager。Manager 是管理者,而 Leader 更多是领导者。作为技术 Leader,需要重点保障核心业务、做技术建设、提升业务效果。为团队设定合理的目标,做好排兵布阵,协调各个团队和资源。所以业内往往称为“技术管理”而不是“管理”。

    技术 Leader 比团队其他同学视野更开阔,对长远的发展趋势看的更准,有技术前瞻性。虽然已经成为团队中最牛逼的程序员之一,但是也要逐渐学会借他人之手写代码,专注于写代码的时间比以前减少很多,而这一点正是优秀程序员转变为技术 Leader 所面临的最大挑战之一。

    架构师是一个非常出名的称谓了,然而却很少有专门的架构师岗位。阿里前几年有架构师岗位,不过现在也回归“技术专家”这样的纯技术岗位了。架构师必须是最出色的程序员,拥有技术深度和广度,有系统性的认知和技术前瞻性。

    架构师通常和技术 Leader 有部分重叠,尤其是在团队规模比较小的时候,两者往往是同一个人。随着软件规模的增大,架构师开始在比技术 Leader 更高的高度上看待问题,这时候架构师和技术 Leader 开始分化为不同的人。架构师也不一定是公司任命的权威领导者,但是在团队内部通常有非权威领导力,是团队内部非常信任的技术领导者。

    这三个发展方向可能会有重叠,对个人来说,还是最好想清楚侧重点是什么。

     

    掌握软件系统方法论

    越是到职业发展的后期,越不能依靠代码本身。所有人都使用着同样的开发语言,掌握着同样的语法和脚本。作为执行者很难体现出优势,总不能说掌握的语法和二方包比别人多吧。优秀的程序员能比别人写出更好的代码,主要还是在如何写代码,以及代码背后的思考,也就是程序员的方法论。

    方法论英文单词是 methodology,也就是说它是关于方法(method)的学问,是关于人们认识世界、改造世界的方法的理论,是人们用什么样的方式、方法来观察事物和处理问题。简单地说,方法论是成熟的思维方式。

    成熟的方法论有很多。前面文章提到的黄金圈法则,是思考问题、分析问题的方法论。领域驱动设计是架构设计方面的方法论,能够帮助解决复杂问题。金字塔原理,是思考问题、解决问题、写作、PPT 演示方面的方法论。系统化思维,是对复杂系统如何观察和分析的理论,也能指导设计复杂系统。

    我们常说的“抓手”、“赋能”、“共建”、“打法”、“对焦”等看起来比较虚的东西,其实就出自于方法论,是方法论中对具体事物和行为背后的客观规律的总结。脉脉上很多人对此嗤之以鼻,成为了大家吐槽的对象,但是这都是很成熟的概念。

    如果长期停留在使用框架的层面,容易陷入工具误区,把使用框架当做技术,思维方式也被局限在框架里。会有一种技术很牛逼的错觉,但是和其他人相比,却没有多少优势,容易被更年轻更有活力的后辈取代。

     

    形成自己的方法论

    方法论的形成需要长期的积累,可以借鉴学习圈理论。学习过程由具体经验、反思观察、抽象概括、主动实验四个阶段,并形成一个闭环。首先学习一个具体的东西,然后停下来对自己的经历进行复盘和思考,再对学习的内容进行抽象,概括成为真正能理解、能吸收的知识,最后再把学习的概念和理论应用于实践并解决现实的问题,如此往复循环。

     

    image.png

    定向钻研一个技术方向,可以加深技术深度,有助于形成方法论。比如,可以定一个目标,让需求上线的时间缩减一半或者同样成本支撑的需求数量翻倍。接下来就需要思考什么样的架构设计能够支撑翻倍的效能,很多情况下都会走向配置化、提升复用、热部署等,接下来你就可以总结出你的方法论了。

    亲自设计一个框架,也是一个不错的选择。既能在纵向深挖,又会有横向拓展的机会。不过这样的尝试一定要以足够的经验积累为前提,否则可能走入误区。跳出日常的习惯,拔高视野,很快就会有领悟,甚至推翻低层次的认知。

    复盘和反思有助于改造认知,实现认知升级。推荐使用黑匣子思维,记录下过程中的思考和问题,能够帮助更好地复盘。关于复盘的方法,推荐阅读《复盘:对过去的事情做思维演练》,书中讲了很多复盘的方法和技巧,是关于复盘的方法论。

    经过思考和训练,你会得到很多经验和认知,会形成自己的思维方式,能够对一类问题形成体系化的深度思考,然后再总结出一些概念进行抽象,使经验适用于更广阔的共性问题,就实现了经验到理论的升华。把自己的理论应用于实践,观察实际效果,对比之前的预期,再领悟新的经验和思考,循环往复,就形成了方法论。

     

    以上就是本文的全部内容了,与君共勉。

    微.信.搜.一.搜.程序之心,每周一三五原创更新。

    展开全文
  • 弊病逐渐凸显出来, 此外“新问题-打补丁-新问题”现象循环往复的出现使得当代的网络核心 即路由器的功能和结构日益复杂, 上述种种现象说明现有的传统网络体系结构亟待革新, 而 SDN 作为一种理想的解决方案则...
  • BAT解密:互联网技术发展之路(1) - 技术发展的驱动力 互联网行业是一个快速发展、快速变化的行业,新的业务、新的机会层出不穷,新的技术如雨后春笋般冒出,NoSQL、大数据、云、Node.js、Docker等,无时不刻...

    BAT解密:互联网技术发展之路(1) - 技术发展的驱动力

    互联网行业是一个快速发展、快速变化的行业,新的业务、新的机会层出不穷,新的技术如雨后春笋般冒出,NoSQL、大数据、云、Node.js、Docker等,无时不刻都在轰炸程序员们的脑袋,难怪中国的程序员都流传一个说法:过了30岁不能做技术工作了,因为技术发展太快了!


    快节奏带来机会,但对于技术人员来说,更多的是带来挑战,甚至有时候是困惑。例如:

    1)Docker很火哦,咱们要不要用呢 ?

    2)Node.js好牛逼啊,我们用上就更牛逼了......

    3)大数据和云是业界发展趋势,我觉得我们也应该跟上技术发展的趋势......

    ......

    还有很多类似的问题和想法,其实归根结底可以归纳为一个统一的问题:是什么推动了一个互联网企业的技术发展

     

    关于这个问题的回答,基本上可以分为几个典型的派别:

    1)潮流派

    潮流派的典型特征就是对于新技术特别热衷,紧跟技术潮流,当有新的技术出现时,迫切的想将新的技术应用到自己的产品中。

    例如:

    NoSQL很火,咱们要大规模的切换为NoSQL;

    大数据好牛逼呀,将我们的MySQL切换为Hadoop吧;

    Node.js是的javascript统一前后端,这样非常有助于我们工作的开展;

    ......等等

     

    2)保守派

    保守派的典型特征和潮流派正好相反,对于新技术抱有很强的戒备心,稳定压倒一切,已经掌握了某种技术,就一直用这种技术打天下。就像那句俗语说的,“如果你手里有一把锤子,那么所有的问题都变成了钉子”,保守派就是拿着一把锤子解决所有的问题。

    例如:

    MySQL咱们用了这么久了,很熟悉了,业务也用MySQL、数据分析也用MySQL、报表也用MySQL吧;

    Java语言我们都很熟,业务用java、工具用java,平台也用java;

    ......等等

     

    3)跟风派

    跟风派与潮流派不同,这里的跟风派不是指跟着技术潮流,而是指跟着竞争对手的步子走。

    简单来说,判断技术的发展就看竞争对手,竞争对手用了咱们就用,竞争对手没用咱们就等等看。 

    例如:

    这项技术腾讯用了么? 腾讯用了我们就用;

    阿里用了Hadoop,他们都在用,肯定是好东西,咱们也要尽快用起来,以提高咱们的竞争力;

    Google都用了Docker,咱们也用吧;

    ......等等

     

    相信不用多说,大家都能看出这几个典型派别存在的问题:

    1)潮流派

    首先,新技术既需要时间成熟,如果刚出来就赶紧用,此时新技术还不怎么成熟,实际应用很可能遇到各种“坑”;

    其次,新技术需要学习,需要花费一定的时间去掌握,这个也是较大的成本;如果等到掌握了结果技术又不适用,就是一种较大的人力浪费了

     

    2)保守派

    保守派的主要问题是不能享受新技术带来的收益,因为新技术很多都是为了解决以前技术存在的固有缺陷。就像汽车取代马车一样,不是量变而是质变,带来的收益不是线性变化的,而是爆发式变化的。

    如果无视技术的发展,形象一点说有了拖拉机,你还偏偏要用牛车。

     

    3)跟风派

    可能很多人都会认为,跟风派与“潮流派”和“保守派”相比,是最有效的策略,既不会承担“潮流派”的风险,也不会遭受“保守派”的损失,花费的资源也少,简直就是一举多得。

    看起来很美妙,但跟风派最大的问题在于如果没有风可跟的时候怎么办。一种情况就是如果你是领头羊怎么办,其他人都准备跟你的风呢;

    另外一种情况就是竞争对手的这些信息并不那么容易获取,即使获取到了一些信息,大部分也是不全面的,一不小心可能就变成邯郸学步了。

    即使有风可跟,其实也还是存在问题的。俗话说:橘生淮南则为橘,生于淮北则为枳,叶徒相似,其实味不同。适用于竞争对手的技术,并不一定适用于自己,盲目模仿可能带来相反的效果。

     

    既然这几个典型派别都存在问题,那么互联网技术发展的驱动力究竟是什么 

     

    这个问题之所以让人困惑,我觉得关键的原因还是在于不管是潮流派、保守派,还是跟风派,都是站在技术本身的角度来考虑问题的,正所谓“不识庐山真面,只缘身在此山中”。

    因此,要想看到庐山真面目,只有跳出技术的角度,从一个更广更高的角度来考虑这个问题,这个角度就是互联网企业的发展。

     

    互联网企业的业务基本上可以大概分为两类:一类是提供“产品”,一类是提供“服务”

    提供产品:360的杀毒软件、苹果的iphone、UC的浏览器。。。。。。等都属于这个范畴,这些产品本质上和传统的制造业产品类似,都是具备了某种“功能”,能够完成某些任务;

    提供服务:百度的搜索、淘宝的购物、微博的资讯、腾讯的IM。。。。。。都属于这个范畴,和“提供产品”的业务不同是,提供服务的业务更加符合互联网的特征和本质:“互联” +“ 网”。所以后续的文章谈论的“互联网技术”,就是指“提供服务的互联网业务的技术”

    “互联”是指这些业务将原本分散的个体连结成了一个庞大的整体,可以将人连接,也可以将信息连接,也可以将数据连接,连接在一起的群体的价值比群体中单个个体的价值之和要大得多;“网”有两种含义:一个是指通过数据网络连接(与传统的电话网络等相比)、一个是指个体互联成“网状”的结构。

     

    一个互联网企业的发展,归根结底就是业务的发展,而影响一个互联网企业的业务发展的主要有3个因素:市场、技术、管理。我称之为业务发展铁三角,任何一个因素的不足都将导致企业业务的发展停滞不前



    如上图,在这个铁三角中,业务是处于三角形的中心,毫不夸张的说,市场、技术、管理的动作都是为了支撑企业业务的发展。市场和管理对业务的影响不在本文的探讨范畴之内,我们主要来探讨一下“技术”和“业务”之间的关系和互相如何影响。

     

    对于“产品”类的业务,答案其实很明显:技术创新不断推动业务的发展

    这个道理和传统的制造行业的产品创新是一样的:产品上的技术创新 -> 带来更强大的功能  -> 推动产品的市场不断扩大 -> 市场扩大竞争更加激烈 -> 反过来又对技术创新提出了更高的要求,如此循环往复,技术创新不断的推动产品的提升、业务的扩展。

     

    对于“产品”类业务,为了追求不断的创新,即使“潮流派”或者“跟风派”存在风险或者问题,但为了能够取得领先,也必须不遗余力的去尝试,否则等到技术没有风险的时候再去用,自己可能已经落后对手一大截了。而且不但要做“潮流派”,还要做“跟风派”,更要做“领头羊”,这样才能在激烈的竞争市场环境下不断的保持领先的优势。

    例如:

    1)苹果开发智能手机,将诺基亚推下王座,自己成为全球手机行业的新王者,就是技术创新驱动产品的典型例子;

    2) 2G时代,UC浏览器独创的云端架构,很好的解决了上网慢的问题;智能机时代,UC浏览器又自主研发全新的U3内核,兼顾高速、安全、智能及可扩展性,这些技术创新是UC浏览器成为了全球最大的第三方手机浏览器最强有力的推动力。

      

    而对于“服务”类的业务,答案和产品类业务正好相反:业务发展推动技术的发展

    为什么会出现截然相反的差别呢?这还需要从“产品”和“服务”的本质差别来看。用户选择一个产品的根本驱动力是其“功能”,例如功能是否强大,外观是否漂亮,用户体验是否良好;而用户选择一个服务的根本驱动力不是功能,而是“规模”。

    例如:选择UC浏览器还是选择QQ浏览器,更多的人是根据个人喜好和体验来决定的;而选择微信还是whatsapp,就不是根据它们之间的功能差异来选择的,而是根据其规模来选择的。就像我更喜欢whatsapp的简洁,但我的的朋友和周边的人都用微信,那我也不得不用微信。

     

    当“规模”成为业务的决定因素后,服务模式的创新成为了业务发展的核心驱动力,而产品只是为了完成服务而提供给用户。以淘宝为例:淘宝提供的“网络购物”是一种新的服务,这种业务与传统的到实体店购物是完全不同的,而为了完成这种业务,需要“淘宝网”、“支付宝”、“一淘”、“菜鸟物流”等多个产品。

    比如说假如我技术创新,开发一个耗电量只有微信的1/10,用户体验比微信好10倍的产品,你觉得现在的微信用户都会抛弃微信,而转投我的这个产品么?我相信绝大部分人都不会,因为微信不是一个互联网产品,而是一个互联网服务,你一个人换到其它类微信类产品是没有意义的。

     

    因此,服务类的业务发展路径是这样的:提出一种创新的服务模式 -> 吸引了一批用户 -> 业务开始发展 -> 吸引了更多用户 -> 服务模式不断完善和创新 -> 吸引越来越多的用户,如此循环往复。在这个发展路径中,技术并没有成为业务发展的驱动力,反过来由于用户规模的不断扩展,业务的不断创新和改进,对技术会提出越来越高的要求,因此是业务驱动了技术发展。

     

    对于“服务”类业务,业务成为了技术发展的驱动力。因此“潮流派”、“跟风派”、“保守派”都是不可取的,什么时候采取什么技术是由业务的规模决定的。


     

    对于“产品”类业务来说,技术的发展和具体的产品有很强的关系,比如说UC浏览器的技术优化和苹果手机的技术优化差别会非常大,因此难以形成一套技术发展的模式;而对于“服务”类业务来说,虽然业务千差万别,但“规模”的发展对技术的影响和推动效果是基本一致的,可以归纳出一套成熟的技术发展体系,本文就试图在这个方向上分几个主题进行一番探索。

     

    前面讲了那么一大堆理论,听起来有点道理,但实践是检验真理的唯一标准,究竟事实是否就是这样呢?我们可以回顾一下几个典型互联网企业的技术发展历程。这里挑选了两个最典型的企业:淘宝、腾讯。之所以挑选这两个,一个是因为大家耳熟能详,另外一个也是因为资料好找。

     

    【淘宝】

    注:以下内容主要摘自《淘宝技术发展》,原文链接:http://kb.cnblogs.com/page/132724/

    淘宝技术发展主要经历了“个人网站”、“Oracle/支付宝/旺旺”、“Java时代1.0”、“Java时代2.0”、“Java时代3.0”、“分布式时代”。我们看看每个阶段的主要驱动力是什么。

    1. 个人网站

    2003年4月7日马云提出成立淘宝,2003年5月10日淘宝就上线了,中间只有1个月,怎么办?淘宝的答案就是:买一个。

    估计大部分人很难想象如今技术牛气冲天的阿里最初的淘宝竟然是买来的,我们看看当初决策的依据:

     

    当时对整个项目组来说压力最大的就是时间,怎么在最短的时间内把一个从来就没有的网站从零开始建立起来?了解淘宝历史的人知道淘宝是在 2003 年 5 月 10 日上线的,这之间只有一个月。要是你在这个团队里,你怎么做?我们的答案就是:买一个来。

     

    大家看到没有,这个时候没有过多考虑技术是否牛逼、没有过多考虑性能是否海量、没有考虑稳定性如何,主要的考虑就是:快!

    因为此时业务要求快速上线,时间不等人,等你花几个月甚至10几个月搞出1个牛逼的系统出来,可能市场机会就没有了,黄花菜都凉了。

    同样,在考虑如何买的时候,淘宝的决策依据主要也是”快“:

     

    买一个网站显然比做一个网站要省事一些,但是他们的梦想可不是做一个小网站而已,要做大,就不是随便买个就行的,要有比较低的维护成本,要能够方便的扩展和二次开发。

    那接下来就是第二个问题:买一个什么样的网站?答案是:轻量一点的,简单一点的

     

    买一个系统是为了”快速可用“,而买一个轻量级的系统是为了”快速开发“,因为系统上线后肯定有大量的需求需要做,这个时候能够快速开发就非常重要。

    从这个实例我们可以看到:淘宝最开始的时候业务要求就是”快“,因此反过来要求技术同样要”快“,业务决定技术。

     

    第一代的技术架构如下图:



    2. Oracle/支付宝/旺旺

    淘宝网推出后,由于正好碰到非典,网购很火爆,加上采取了成功的市场运作,流量和交易量迅速上涨,业务发展很快,在 2003 年底,MySQL 已经撑不住了。

    一般人或者团队在这个时候,可能就开始优化系统、优化架构了、分拆业务了,因为这些是大家耳熟能详也很拿手的动作。那我们来看看淘宝这个时候怎么采取的措施:

    技术的替代方案非常简单,就是换成 Oracle。换 Oracle 的原因除了它容量大、稳定、安全、性能高之外,还有人才方面的原因。

     

    可以看出这个时候淘宝的策略主要还是”买“,买更高配置的Oracle,这个是当时情况下最快的方法。

    除了购买Oracle,后来为了优化,又买了更牛逼的存储:

    后来数据量变大了,本地存储不行了。买了 NAS(Network Attached Storage:网络附属存储),NetApp 的 NAS 存储作为了数据库的存储设备,加上 Oracle RAC(Real Application Clusters,实时应用集群)来实现负载均衡。

     

    我们思考一下,为什么淘宝在这个时候继续采取“买”的方式来快速解决问题呢?我们可以从时间上看出端倪:此时离刚上线才半年不到,业务飞速发展,最快的方式支撑业务的发展还是去买。如果说第一阶段买的是“方案”,这个阶段买的就是“性能”。

     

    换上Oracle和昂贵的存储后,第二代架构如下:




    3. Java时代1.0 - 脱胎换骨

    淘宝切换到Java的原因很有趣,主要因为找了一个PHP的开源连接池SQL Relay连接到Oracle,而这个代理经常死锁,死锁了就必须重启,而数据库又必须用Oracle,于是决定换个开发语言。最后淘宝挑选了Java,而且当时挑选Java,也是请Sun公司的人,这帮人很牛逼,先是将淘宝网站从PHP热切换到了Java,后来又做了支付宝。

    这次切换的最主要原因是因为技术影响了业务的发展,你说动不动就死锁、然后就要重启,这个是对用户业务严重的影响。从业务的角度来看这是不得不解决的技术问题。

     

    但这次淘宝为什么没有去“买”,是有点疑惑的地方。我们看最初选择SQL Relay的原因:

    但对于 PHP 语言来说它是放在 Apache 上的,每一个请求都会对数据库产生一个连接,它没有连接池这种功能(Java 语言有 Servlet 容器,可以存放连接池)。那如何是好呢?这帮人打探到 eBay 在 PHP 下面用了一个连接池的工具,是 BEA 卖给他们的。我们知道 BEA 的东西都很贵,我们买不起,于是多隆在网上寻寻觅觅,找到一个开源的连接池代理服务 SQLRelay”

     

    不清楚当时到底有多贵,Oracle都可以买,连接池买不起 ?所以我个人感觉这次切换语言,更多的是为以后业务发展做铺垫,毕竟当时PHP语言远远没有Java那么火,那么好招人。淘宝选择Java语言的理由可以从侧面验证这点:

    “Java 是当时最成熟的网站开发语言,它有比较良好的企业开发框架,被世界上主流的大规模网站普遍采用,另外有 Java 开发经验的人才也比较多,后续维护成本会比较低。”

     

    从PHP改为Java后,第三代技术架构如下:



    4. Java时代2.0 - 坚若磐石

    Java2.0时代,淘宝做了很多优化工作:数据分库、放弃 EJB、引入 Spring、加入缓存、加入 CDN、采用开源的 JBoss。为什么在这个时候要做这些动作? 原文作者很好的概括了做这些动作的原因:

    这些杂七杂八的修改,我们对数据分库、放弃 EJB、引入 Spring、加入缓存、加入 CDN、采用开源的 JBoss,看起来没有章法可循,其实都是围绕着提高容量、提高性能、节约成本来做的”

    我们思考一下,为什么在前面的阶段,淘宝考虑的都是“快”,而现在开始考虑“容量、性能、成本”了呢?而且为什么这个时候不采取“买”的方式来解决容量、性能、成本问题呢?

    简单来说,就是“买”也搞不定了,此时的业务发展情况是这样的:

    随着数据量的继续增长,到了 2005 年,商品数有 1663 万,PV 有 8931 万,注册会员有 1390 万,这给数据和存储带来的压力依然山大,数据量大,性能就慢。”

     

    原有的方案存在的固有缺陷,随着业务的继续发展,已经不是靠“买”能够解决的了,此时必须从整个架构上去进行调整和优化。比如说Oracle再牛逼,在做like类搜索的时候,也不可能做到纯粹的搜索系统如Solr、Sphinx等的性能,因为这是机制决定的。

     

    另外,随着规模的增大,纯粹靠买的一个典型问题开始成为重要的考虑因素,那就是成本。当买一台两台Oracle的时候,可能对成本并不怎么关心,但如果要买100台Oracle,成本就是一个关键因素了。这就是“量变带来质变”的一个典型案例。

     

    Java 架构经过各种优化,第四代技术架构如下:


    5. Java时代3.0 和分布式时代

    Java时代3.0时代我个人认为是淘宝技术飞跃的开始,简单来说就是淘宝技术从商用转为“自研”,典型的就是去IOE化。

    分布式时代我认为是淘宝技术的修炼成功,到了这个阶段,自研技术已经自成一派,除了支撑本身的海量业务外,也开始影响整个互联网的技术发展。

    具体的原因这里就不详细分析,留给读者按照前面的思路去分析。


    【手机QQ】

    注:以下内容主要摘自《QQ1.4亿在线背后的故事》

    手机QQ的发展历程按照用户规模可以粗略划分为4个阶段:十万级、百万级、千万级、亿级,不同的用户规模,IM后台的架构也不同,而且基本上都是用户规模先上去,然后产生各种问题,倒逼技术架构升级。

    1. 十万级 - IM1.X

    最开始的手机QQ后台如下,可以说是简单的不能再简单,普通得不能再普通的一个架构了(是否会感叹原来神一样的公司开始也是屌丝一个呀 ):


    2. 百万级 - IM2.X

    业务发展:2001年,QQ同时在线突破一百万

    第一代架构很简单,但也很明显不可能支撑百万级的用户规模,主要的问题有:

    1)以接入服务器的内存为例,单个在线用户的存储量约为2KB,索引和在线状态 50字节,好友表 400个好友 * 5字节/好友 = 2000字节,大致来说,2G内存只能支持一百万在线用户;

    2)CPU/网卡包量和流量/交换机流量等瓶颈;

    3)单台服务器支撑不下所有在线用户/注册用户;

     

    于是针对这些问题做架构改造,IM2.X的最终架构如下


    3. 千万级 - IM3.X

    业务发展:2005年,QQ同时在线突破一千万。

    第二代架构支撑百万级用户是OK的,但支撑千万级用户又有问题,表现如下:

    1)同步流量太大,状态同步服务器遇到单机瓶颈;

    2)所有在线用户的在线状态信息量太大,单台接入服务器存不下,如果在线数进一步增加,则甚至单台状态同步服务器也存不下;

    3)单台状态同步服务器支撑不下所有在线用户;

    4)单台接入服务器支撑不下所有在线用户的在线状态信息;

     

    针对这些问题,架构需要继续改造升级,IM3.X的最终架构如下


    4. 亿级用户 - IM1.X

    业务发展:2010.03,QQ同时在线人数过亿

    第三代架构此时也不适应了,主要问题有:

    1)灵活性很菜:“昵称”长度增加一半,需要两个月、增加“故乡”字段,需要两个月、最大好友数从500变成1000,需要三个月

    2)无法支撑这些关键功能:上万好友、隐私权限控制、PC QQ与手机QQ别互踢、微信与QQ互通、异地容灾

    除了不适应外,还有一个更严重的问题:

    “IM后台从1.0到3.5都是在原来基础上做改造升级,但是:持续打补丁已经难以支撑亿级在线,IM后台4.0必须从头开始,重新设计实现!”

    决定重新打造一个这么复杂的系统,不得不佩服当时决策人的勇气和魄力!!

     

    重新设计的IM4.0架构如下,和之前的架构相比,架构本身都拆分为两个主要的架构:存储架构和通信架构:





    通过上面对淘宝技术发展和手机QQ的架构发展,我们可以看到,这两个实例证明了我们之前的推断:对于提供互联网服务的企业来说,互联网技术的发展,背后的驱动力是业务的发展

     

    了解到互联网技术发展的根本驱动力是业务的发展后,接下来我们就需要继续分析:业务如何驱动技术的发展、技术体系会按照什么样的路径发展。欲知后事如何,且听下回分解


    ==================================================

    转载注明出处:http://blog.csdn.net/yunhua_lee/article/details/44938671


    展开全文
  • 在当今社会,工业科技革命的迅速崛起,大数据分析技术、物联网技术、音频技术等的相互融合快速发展,在生物、化学、人工智能等领域有了较大的市场和研究价值。对于音频技术在这之中起到了承上启下、不可或缺的一部分...
  • 健康管理是一个连续的、长期的、循环往复、始终贯穿的过程,依托互联网+实时健康监测智能穿戴设备+云数据为基础,利用智能健康检测设备、无线通讯、互联网+实体、云计算+人工智能等诸多领域的前沿技术,智能健康管理...
  • 技术发展的驱动力

    千次阅读 2016-06-14 08:46:26
    互联网行业是一个快速发展、快速变化的行业,新的业务、新的机会层出不穷,新的技术如雨后春笋般冒出,NoSQL、大数据、云、Node.js、Docker等,无时不刻都在轰炸程序员们的脑袋,难怪中国的程序员都流传一个说法:过...
  • 一个 集体电路的制造需要数百道的步骤,便是在这6个厂区中循环往复,多层建构而成,将MOS原件和电路设计的导线如盖房子 一样,分层堆叠在晶圆上。每道制程中的量产规格,包括量测数据和相关制程参数设定,是采购和...
  • 区块链共识算法的发展现状与展望

    千次阅读 2019-11-13 18:21:00
    来源:平行区块链摘 要共识算法是区块链技术的核心要素, 也是近年来分布式系统研究的热点. 本文系统性地梳理和讨论了区块链发展过程中的 32 种重要共识算法, 介绍了传统...
  • 浅谈软件定义网络(SDN)技术研究现状和发展趋势 长久以来,硬件在网络世界中保持着至高无上的地位。直到2008年斯坦福大学的学者提出 OpenFlow[1],并于2009年将其扩展为 SDN(software-defined networking)概念[2...
  • 从域 X 生成域 Y,再从 Y 生成回 X,循环往复。假定两个映射关系,分别是 G:X -> Y,以及 F:Y -> X,并提出了前向一致性损失和反向一致性损失: x−>G(x)−>F(G(x))≃xx -> G(x) -> F(G(x)) \simeq xx−>G(x)−>F...
  • 5.在实践中找出新的问题,如此循环往复。 笛卡尔的哲学中,的确夹杂着无数唯心主义的成分,但是我们并不能因此而抹杀他对科学和科学方法的贡献。在笛卡尔之前的科学家并非不懂研究的方法,但是他们了解的研究方法...
  • 模型预测控制系列讲解(二)模型预测控制算法发展进程 后续更新
  • 冷链物流市场三个重要的发展趋势

    千次阅读 2019-03-02 09:41:22
    在中国生鲜消费需求逐年增长和中国消费者对食品的质量和安全的要求越来越高的大背景下,近年来中国冷链物流市场发展迅猛。据统计,2018年中国冷链市场整体规模将突破2,500亿元,2022年将达到4,500亿元规模。 在快速...
  • 回顾一下web技术的发展历史,并可预见一下未来的发展。除了HTTP/2.0这个还未正式纳入规范的技术,Cowboy与所有这些技术都是兼容的。
  • 新的问题发现以后,会在这个闭环里面进行循环往复的修正,这就是农行的数据质量保证机制,通过这个机制能够实现数据标准管理和元数据管理的一个不断地持续改进。   2.4 数据管理技术平台 为了落实前面对应的各项...
  • 回顾计算机业发展的历史,我们不难看出,硬件的性能与软件的处理能力是相辅相成的。 今天我们所面临的云计算以及前几年SUN公司提出的网格计算都是软件为了适应或者说更好地发挥硬件的性能而进行的进化性的更新。...
  • 其实,我们每天勤勤恳恳工作,期待着月末收到工资,然后花掉它,如此循环往复,就像是一只在轮子上疯狂奔跑的仓鼠,一直在奔跑,也一直停留在原地。     老板雇佣你,一定是按照市场价格来雇佣你,而...
  • javascript篇 一、数据类型 JavaScript 有几种类型 基本数据类型:undefined、null、boolean、number、string、symbol(es6的新数据类型) 引用数据类型:object、array、function(统称为object) ...
  • 国家皮肤与免疫疾病临床医学研究中心与国家风湿病数据中心发起并编撰的《类风湿性关节炎发展报告》(以下简称“发展报告”)在第三届辉瑞炎症与免疫论坛上正式发布。这是目前中国类风湿关节炎(RA)...
  • 1、”上山-登顶-下山“存在于职业生涯的多个阶段,这是一个循环往复的过程,尤其对于某一方面的测试技能来说; 2、上山时,一定要注意选择工作中需要的”山和你感兴趣的”山“,切莫目标太多; 3、回顾之前...
  • 但是,不要企图在这里找到你自己发展的规划和指定好的发展航向和行程。看了这篇文章,能够收到启发,受到鼓舞,也就是本文的一个成功的地方了。如果能够切实的给你指导发展方向,那更是荣幸备至。但是,每个人的兴趣...
  • 写作本文的初衷是想和大家分享垃圾收集( Garbage Collection )技术简单而有趣的发展史。动笔之前,我站在窗边,望了望正在小区里装运垃圾的清洁车。和生活中环卫工人们清运垃圾的工作相似,软件开发里的垃圾收集...
  • 我想,如果是打算走进C++编程的同志们,请好好看完这篇文章,或许,对你的发展有所启发。但是,不要企图在这里找到你自己发展的规划和指定好的发展航向和行程。看了这篇文章,能够收到启发,受到鼓舞,也就是本文的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,126
精华内容 1,250
关键字:

发展是循环往复的