Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript #1

Open
bigggge opened this issue May 18, 2017 · 0 comments
Open

JavaScript #1

bigggge opened this issue May 18, 2017 · 0 comments
Labels

Comments

@bigggge
Copy link
Member

bigggge commented May 18, 2017

介绍JavaScript的基本数据类型

6种原始数据类型

Undefined、Null、Boolean、Number 和 String

对象类型 Object

ES6 新增 Symbol

保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。

介绍JavaScript有哪些内置对象?

Object 是 JavaScript 中所有对象的父对象

数据封装类对象:Object、Array、Boolean、Number 和 String
其他对象:Function、Arguments、Math、Date、RegExp、Error

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

在 ECMAScript 中,变量可以存在两种类型的值,即原始值引用值

原始值
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。

引用值
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。

如何将字符串转化为数字,例如'12.3b'?

parseFloat('12.3b');

JavaScript原型,原型链 ? 有什么特点?

1.JavaScript 不包含传统的类继承模型,而是使用prototype原型模型。

2.函数的prototype属性指向函数的原型对象。

3.每个对象都有一个__proto__属性,指向函数的原型对象

4.每个对象都有一个指向它原型对象的链接。这个原型对象又有自己的原型,直到Object.prototype,它的的原型为 null 为止,组成这条链的最后一环,这种一级一级的链结构就称为原型链)。

5.当查找一个对象的属性时,会向上遍历原型链,直到找到给定名称的属性为止

原型对象的 constructor 属性指向 prototype 属性所在函数

hasOwnProperty() 检测一个属性是存在于实例中,还是存在于原型中

先有Object.prototype(原型链顶端),Function.prototype继承Object.prototype而产生,最后,FunctionObject和其它构造函数继承Function.prototype而产生。

详见博客:图解原型链

typeof 和 instanceof

typeof 操作符(和 instanceof 一起)或许是 JavaScript 中最大的设计缺陷, 因为几乎不可能从它们那里得到想要的结果。

Value               Class      Type
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object (function in Nitro/V8)
new RegExp("meow")  RegExp     object (function in Nitro/V8)
{}                  Object     object
new Object()        Object     object

typeof 大多数情况下都返回 object

建议使用:

Object.prototype.toString.call([])    // "[object Array]"
Object.prototype.toString.call({})    // "[object Object]"
Object.prototype.toString.call(2)    // "[object Number]"

instanceof:

每个对象都有一个__proto__属性,指向创建该对象的函数的 prototype,即原型对象

 console.log(Object instanceof Object);//true 
 console.log(Function instanceof Function);//true 
 console.log(Number instanceof Number);//false 
 console.log(String instanceof String);//false 

 console.log(Function instanceof Object);//true 

 console.log(Foo instanceof Function);//true 
 console.log(Foo instanceof Foo);//false

实例的__proto__链和构造函数的 prototype 是不是指向同一个原型对象

function instance_of(a, b) {
    var bPrototype = b.prototype;// 取 b 的显示原型
    a = a.__proto__;// 取 a 的隐式原型
    while (true) {
        if (a === null)
            return false;
        if (bPrototype === a)
            return true;
        a = a.__proto__;
    }
}

示例:

 // 为了方便表述,首先区分左侧表达式和右侧表达式
 FooL = Foo, FooR = Foo; 
 // 下面根据规范逐步推演
 O = FooR.prototype = Foo.prototype 
 L = FooL.__proto__ = Function.prototype 
 // 第一次判断
 O != L 
 // 循环再次查找 L 是否还有 __proto__ 
 L = Function.prototype.__proto__ = Object.prototype 
 // 第二次判断
 O != L 
 // 再次循环查找 L 是否还有 __proto__ 
 L = Object.prototype.__proto__ = null 
 // 第三次判断
 L == null 
 // 返回 false

JavaScript创建对象的几种方式?

1.对象字面量

var myHonda = {
    color: "red",
    wheels: 4,
    engine: {cylinders: 4, size: 2.2}
};

2.工厂模式

function createPerson(name, age, job){
            var o = new Object();
            o.name = name;
            o.age = age;
            o.job = job;
            o.sayName = function(){
                alert(this.name);
            };    
            return o;
        }
        
        var person1 = createPerson("Nicholas", 29, "Software Engineer");
        var person2 = createPerson("Greg", 27, "Doctor");

缺点是无法知道对象的类型

3.构造函数模式

        function Person(name, age, job){
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = sayName;
        }
        
        function sayName(){
            alert(this.name);
        }
        
        var person1 = new Person("Nicholas", 29, "Software Engineer");
        var person2 = new Person("Greg", 27, "Doctor");
        
        person1.sayName();   //"Nicholas"
        person2.sayName();   //"Greg"

缺点是在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域名不副实

4.原型模式

        function Person(){
        }
        
        Person.prototype.name = "Nicholas";
        Person.prototype.age = 29;
        Person.prototype.job = "Software Engineer";
        Person.prototype.sayName = function(){
            alert(this.name);
        };
        
        var person1 = new Person();
        person1.sayName();   //"Nicholas"
        
        var person2 = new Person();
        person2.sayName();   //"Nicholas"

5.组合使用方式

JavaScript如何实现继承?

许多OO语言支持接口继承和实现继承。
js只支持依靠原型链的实现继承。

原型继承->引用类型值被所有实例共享->构造函数继承->超类原型中定义的方法对子类不可见,也不能函数复用->组合继承

原型继承

function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {}

// 设置Bar的prototype属性为Foo的实例对象			
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

// 修正Bar.prototype.constructor为Bar本身,防止clone时错误,
// var bar1 = bar.constructor();

Bar.prototype.constructor = Bar;

var test = new Bar() // 创建Bar的一个新实例

原型链继承的问题:

1.引用类型值被所有实例共享

2.创建子类型的实例时,不能在不影响所有实例的情况下向超类型的构造函数中传递参数。

为解决引用类型值被共享的问题,可使用构造函数继承,(在Sub上Super中的对象初始化代码)

 function SuperType(){
     this.colors = ["red", "blue", "green"];
  }

  function SubType(){  
      //inherit from SuperType
      SuperType.call(this);
  }

  var instance1 = new SubType();
  instance1.colors.push("black");
      alert(instance1.colors);    //"red,blue,green,black"
        
  var instance2 = new SubType();
        alert(instance2.colors);    //"red,blue,green"

组合继承:
超类型的原型中定义的方法对子类型不可见,也不能函数复用,因为每次 new 都会创建新的函数。所以采用组合继承。

    function SuperType(name){
        this.name = name;
        this.colors = ["red", "blue", "green"];
    }
    
    SuperType.prototype.sayName = function(){
        alert(this.name);
    };

    function SubType(name, age){  
        SuperType.call(this, name);
        
        this.age = age;
    }

    // 解决 超类型的原型中定义的方法对子类型不可见 问题
    SubType.prototype = new SuperType();
    
    SubType.prototype.sayAge = function(){
        alert(this.age);
    };
    
    var instance1 = new SubType("Nicholas", 29);
    instance1.colors.push("black");
    alert(instance1.colors);  //"red,blue,green,black"
    instance1.sayName();      //"Nicholas";
    instance1.sayAge();       //29

    var instance2 = new SubType("Greg", 27);
    alert(instance2.colors);  //"red,blue,green"
    instance2.sayName();      //"Greg";
    instance2.sayAge();       //27

Javascript作用链域?

JavaScript 是一个单线程语言,意味着同一时间只能执行一个任务, 它首先默认进入全局执行环境,执行上下文定义了变量或函数有权访问的其它数据

可以将每个执行上下文抽象为一个对象并有三个属性:

executionContextObj = {
    // 作用域链
    scopeChain: { /* 变量对象(variableObject)+ 所有父执行上下文的变量对象*/ }, 
    // 变量对象
    variableObject: { /*函数 arguments/参数,内部变量和函数声明 */ }, 
    this: {} 
}

每次你试图访问函数执行上下文中的变量时,总是从自己的变量对象开始查找,如果没找到,将继续搜索作用域链,检查每一个执行上下文的变量对象,去寻找匹配的值

JavaScript中的作用域和执行上下文

谈谈this的理解。

1.在全局运行上下文中(在任何函数体外部),this指代全局对象,无论是否在严格模式下。

// 在浏览器中,全局对象为 window 对象:
console.log(this === window); // true

2.直接调用函数,this的值会默认设置为全局对象,在严格模式下,this将会默认为undefined

function f1(){
  return this;
}

f1() === window; // true

3.当以对象里的方法的方式调用函数时,它们的 this 是调用该函数的对象.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

当 o.f() 被调用时,函数内的this将绑定到o对象。

4.当一个函数被作为一个构造函数来使用(使用new关键字),它的this与即将被创建的新对象绑定。

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37

5.call 和 apply 都是为了改变某个函数运行时的上下文

function add(c, d){
  return this.a + this.b + c + d;
}

var o = {a:1, b:3};

add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

当一个对象没有某个方法,但是其他对象有,我们可以借助call或apply用其它对象的方法来操作

.call() 和 .apply() 的区别?

function a(xx) {        
    this.b = xx;
}
var o = {};
a.apply(o, [5]);
alert(a.b);    // undefined
alert(o.b);    // 5

call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。

对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。  

bind()方法会创建一个新函数,、第一个参数作为 this,第二个以及以后的参数加上新函数调用时传入的参数按照顺序作为原函数的参数。

详见博客JavaScript call() , apply() , bind()方法

setTimeout

一个 JavaScript 运行时包含了一个待处理的消息队列。每一个消息都与一个函数相关联。当栈为空时,从队列中取出一个消息进行处理。这个处理过程包含了调用与这个消息相关联的函数。当栈再次为空的时候,也就意味着消息处理结束。

setTimeout 函数会在一个时间段过去后在队列中添加一个消息。如果有其它消息,setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少的时间 而非确切的时间。

同步和异步的区别,如何实现异步编程?

同步:如果在函数A返回的时候,调用者就能够得到预期结果(即拿到了预期的返回值或者看到了预期的效果),那么这个函数就是同步的。

异步:如果在函数A返回的时候,调用者还不能够得到预期结果,而是需要在将来通过一定的手段得到,那么这个函数就是异步的。

回调函数

var fn = function (callback) {
    callback('callback');
};

fn(function (value) {
    console.log(value);
});

回调函数使用简单,容易理解,缺点就是存在耦合也容易造成 callback hell。

事件监听

事件监听模式中,任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

$('#button').click(function () {
     console.log('click');
});

从本质上说,事件监听也是一种观察者模式。

观察者模式

观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

详见后文

Promise

详见后文

Async + Await

详见后文

RxJS

详见后文

详见博客:浅谈JavaScript中的异步编程

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

内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回了之后。换句话说,这些函数可以记忆它被创建时候的环境。

所以闭包的本质源自两点,词法作用域函数当作值传递,一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量

词法作用域关心的是函数在哪里声明的

所有的函数在被执行的时候都是闭包,因为它可以访问外部作用域的数据

应用

1.每次触发自执行函数时,都相当于将当前循环的变量i存储了下来

   for (var i = 0; i < arr.length; i++) {
     (function (arg) {
         arr[i].onclick = function () {
             alert(arg);
         }
     })(i);
  }

2.管理私有变量和私有方法

var Counter = (function() {
  var privateCounter = 0;
  // “闭包”内的函数可以访问 privateCounter 变量
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

3.将代码封装成一个闭包形式,合适的时候再使用,比如实现柯里化(是一种实现多参数函数的方法),createAssigner 返回了一个函数,这个返回的函数引用了外面的一个变量。

 
 var createAssigner = function (keysFunc, undefinedOnly) {
    return function (obj) {
        //...
        keys = keysFunc(source)
        //...
        return obj;
    };
};

createAssigner(allKeys)(a, b)
createAssigner(keys)(c, b)

内存泄露是指你用不到的变量,依然占居着内存空间,不能被再次利用起来。闭包里面的变量是我们需要的变量,不应说是内存泄露

初识JavaScript闭包

eval是做什么的?

eval()函数执行表示为字符串形式的JavaScript代码。

避免在不必要的情况下使用eval eval() 是一个危险的函数, 你的代码可能被恶意方在使用方的机器上使用恶意代码。

LINK

什么是window对象? 什么是document对象?

BOM(浏览器对象模型)的核心对象是window,它既是通过js访问浏览器窗口的接口,又是ecmascript规定的global对象

document对象是HTMLDocument的一个实例,表示整个html页面,也是window对象的一个属性。

null,undefined 的区别?

使用var声明但未初始化时,变量值为undefined。

null表示一个空对象指针。

没有必要声明一个值为undefined,但是可以保存为null以体现null作为空指针的惯例。

http://bonsaiden.github.io/JavaScript-Garden/zh/#core.undefined

写一个通用的事件函数

var EventUtil = {

    addHandler: function(element, type, handler){
        if (element.addEventListener){
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent){
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    
    getClipboardText: function(event){
        var clipboardData =  (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
    },
    
    getEvent: function(event){
        return event ? event : window.event;
    },

    getTarget: function(event){
        return event.target || event.srcElement;
    },
    
    preventDefault: function(event){
        if (event.preventDefault){
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },

    removeHandler: function(element, type, handler){
        if (element.removeEventListener){
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent){
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    
    stopPropagation: function(event){
        if (event.stopPropagation){
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
      }
    };

事件是?IE与Netscape的事件机制有什么区别?

js和html之间的交互是通过事件实现的,就是文档和浏览器窗口中发生的一些交互瞬间。

IE的事件流为事件冒泡

Netscape的事件流为事件捕获(很少使用)

讲一讲事件委托机制

为解决事件处理程序过多问题,事件委托利用事件冒泡机制,指定一个事件处理程序,管理某一类型的所有事件。如:click会一直冒泡到document层次。

document.getElementById("parent-list").addEventListener("click", function(e) {
    if(e.target && e.target.nodeName == "LI") {
        console.log("List item ", e.target.id.replace("post-"), " was clicked!");
    }
});

stopPropagation和preventDefault

stopPropagation()

有时我们希望事件在特定节点执行完之后不再传递,可以使用事件对象的 stopPropagation() 方法

// 在弹出对话框上点击时, 不进行任何页面操作, 并阻止冒泡
document.getElementById('dialog').onclick = function(ev) {
    ev.stopPropagation();
};
// 在 documentElement 节点上监听到点击事件时, 隐藏对话框
document.documentElement.onclick = function(ev) {
    document.getElementById('dialog').style.display = 'none';
};

preventDefault()

阻止将要执行的浏览器默认动作

<a id="link" href="http://w3c.org">W3C 首页链接</a>
<script>
    //在新窗口, 打开页面
    document.getElementById('link').onclick = function(ev) {
        // 阻止浏览器默认动作 (页面跳转)
        ev.preventDefault();
        // 在新窗口打开页面
        window.open(this.href);
    };
</script>

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

ECMAScript5 引入严格模式,

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

	function Foo() {}
	function Bar() {}
	Bar.prototype = new Foo();
	
	new Bar() instanceof Bar; // true
	new Bar() instanceof Foo; // true
	
	// 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
	Bar.prototype = Foo;
	new Bar() instanceof Foo; // false

var a = new A();a instance A 不一定返回true,见例子

function A() {
    return function B() {};
}
var a = new A();
console.log(a instanceof A); // false

new 操作符具体干了什么?

当代码 new Foo(...) 执行时:

1.一个新对象被创建。它继承自Foo.prototype.
foo.__proto__ === Foo.prototype

2.构造函数 Foo 被执行。执行的时候,相应的传参会被传入,同时this会被指定为这个新实例。

3.如果构造函数返回了一个“对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象,

ps:一般情况下构造函数不返回任何值,不过用户如果想覆盖这个返回值,可以自己选择返回一个普通对象来覆盖。当然,返回数组也会覆盖,因为数组也是对象。

JavaScript中哪一个函数,执行时对象查找时,永远不会去查找原型?

hasOwnProperty() 检测一个属性是存在于实例中,还是存在于原型中

Object.prototype.bar = 1; 
var foo = {goo: undefined};

foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true

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

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

图片延迟加载

<body>
<img data-src="http://farm8.staticflickr.com/7060/6969705425_0905bf6bba_o.jpg" src="blank.gif" class="lazy">
<script>
    !function (window) {
   
        function loadImage(el) {
            var img = new Image();
            var src = el.getAttribute('data-src');
            img.onload = function () {
                if (!!el.parent)
                    el.parent.replaceChild(img, el)
                else
                    el.src = src;
            };
            img.src = src;
        }

        function elementInViewport(el) {
            var rect = el.getBoundingClientRect();
            return (
                rect.top >= 0 && rect.left >= 0 &&
                rect.top <= (window.innerHeight || document.documentElement.clientHeight)
            )
        }

        var images = [];
        var $img = $q('img.lazy');
        var processScroll = function () {
            for (var i = 0; i < images.length; i++) {
                if (elementInViewport(images[i])) {
                    loadImage(images[i]);
                }
            }
        };

        for (var i = 0; i < $img.length; i++) {
            images.push($img[i]);
        }
        processScroll();
        addEventListener('scroll', processScroll);

    }(window)
</script>
</body>

图片延迟加载

单页应用原理

  1. 拦截a标签的默认跳转动作。
  2. 使用Ajax请求新页面。
  3. 将返回的Html替换到页面中。
  4. 使用HTML5的History API或者Url的Hash修改Url。

谈一谈你对ECMAScript6的了解?

箭头函数

函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 });
// id: 42

上面代码中,setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到100毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。

Class

Class 是基于原型继承的语法糖

  class Circle {
        constructor(radius) {
            this.radius = radius;
            Circle.circlesMade++;
        };
        static draw(circle, canvas) {
            // Canvas绘制代码
        };
        static get circlesMade() {
            return !this._count ? 0 : this._count;
        };
        static set circlesMade(val) {
            this._count = val;
        };
        area() {
            return Math.pow(this.radius, 2) * Math.PI;
        };
        get radius() {
            return this._radius;
        };
        set radius(radius) {
            if (!Number.isInteger(radius))
                throw new Error("圆的半径必须为整数。");
            this._radius = radius;
        };
    }

类似于

function Circle(radius) {
        this.radius = radius;
        Circle.circlesMade++;
    }
    Circle.draw = function draw(circle, canvas) { /* Canvas绘制代码 */ }
    Object.defineProperty(Circle, "circlesMade", {
        get: function() {
            return !this._count ? 0 : this._count;
        },
        set: function(val) {
            this._count = val;
        }
    });
    Circle.prototype = {
        area: function area() {
            return Math.pow(this.radius, 2) * Math.PI;
        }
    };
    Object.defineProperty(Circle.prototype, "radius", {
        get: function() {
            return this._radius;
        },
        set: function(radius) {
            if (!Number.isInteger(radius))
                throw new Error("圆的半径必须为整数。");
            this._radius = radius;
        }
    });

Template Strings 模板字符串

// 字符串中嵌入变量
var name = "Bob", time = "today";1
Hello ${name}, how are you ${time}?

http://babeljs.io/learn-es2015/

谈谈你对 ES6 新的声明变量的方式的一些看法

let

1.let声明的变量拥有块级作用域;ES5 只有全局作用域和函数作用域,没有块级作用域

// 用来计数的循环变量泄露为全局变量
var s = 'hello';

for (var i = 0; i < s.length; i++) {
  console.log(s[i]);
}

console.log(i); // 5

2.var命令会发生”变量提升“现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

const

const声明一个只读的常量。一旦声明,常量的值就不能改变

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

const 声明的是常量,真的不能被改变吗?

const保证的并不是变量的值不得改动,而是变量指向的那个内存地址不得改动

对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

你提到了 Set 类型,那你讲下对 Es6 里 Map 类型的看法。

Set

它类似于数组,但是成员的值都是唯一的,没有重复的值

Map

它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

var m = new Map();
var o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

模块化编程怎么做,AMD、CMD规范区别?

1.简单的模块:函数 ->

2.闭包,IIFE 模式->

3.CommonJS 规范加载模块是同步的,只有加载完成,才能执行后面的操作。

4.AMD 规范则是非同步加载模块,允许指定回调函数, 推崇依赖前置,提前执行,在定义模块的时候就引入了其他模块,在模块当中已经是可用状态。

5.CMD提倡依赖就近,在需要使用到某个模块的时候,才进行引入。->

6.Webpack 是一个用于现代 JavaScript 应用的模块打包器(module bundler),它能够分析你的项目结构,找到 JavaScript 模块以及一些浏览器无法运行的语言(Scss,TypeScript等),并将其打包成合适的格式供浏览器使用。->

7.ES6 模块

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

// app.js
import * as math from "lib/math";
console.log("2π = " + math.sum(math.pi, math.pi));

// otherApp.js
import {sum, pi} from "lib/math";
console.log("2π = " + sum(pi, pi));

// export default and export *
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
    return Math.exp(x);
}

// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));

模块化用于解决解决命名冲突与文件依赖
LINK

详见博客JavaScript的模块化编程

函数声明和函数表达式

// 方法一:函数声明
function foo() {}

// 方法二:函数表达式
var foo = function () {};

JavaScript 中存在变量声明被**提升(hoisting)**的机制,变量(函数)的声明会被提升到作用域的最前面

documen.write和 innerHTML的区别

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

DOM操作?

方法 描述
getElementById() 返回带有指定 ID 的元素。
getElementsByTagName() 返回包含带有指定标签名称的所有元素的节点列表(集合/节点数组)。
getElementsByClassName() 返回包含带有指定类名的所有元素的节点列表。
appendChild() 把新的子节点添加到指定节点。
removeChild() 删除子节点。
replaceChild() 替换子节点。
insertBefore() 在指定的子节点前面插入新的子节点。
createAttribute() 创建属性节点。
createElement() 创建元素节点。
createTextNode() 创建文本节点。
getAttribute() 返回指定的属性值。
setAttribute() 把指定属性设置或修改为指定的值。

内存泄漏?

IE 6, 7 使用引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄露。引用计数的含义是跟踪记录每个值被引用的次数,赋值时+1,引用这个值的变量又取得另一个变量引用次数-1

标记-清除算法给所有变量加上标记,然后去掉环境中的变量和变量引用的变量,此后销毁带标记的值。

从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。

polyfill 方案?

Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。MDN

    var create = (function () {
    function Temp() {
    }
    return function (O) {
        Temp.prototype = O;
        var obj = new Temp();
        Temp.prototype = null; 
        if (arguments.length > 1) {
            var Properties = Object(arguments[1]);
            for (var prop in Properties) {
                    obj[prop] = Properties[prop];
            }
        }
        return obj;
    };
})();

indexOf() 方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回-1。MDN

function indexOf(array, searchElement) {
     if (array.length === 0) {
         return -1;
     }
     var key = 0;
     while (key < array.length) {
         if (array[key] === searchElement) {
             return key;
         }
         key++;
     }
     return -1;
 }

详见博客Underscore.js 源码学习笔记

设计模式

单例模式

一个类只能有一个实例化对象

function singleton( fn ){
    var result;
    return function(){
        return result || (result = fn.apply(this, arguments));
    }
}

简单工厂模式

工厂模式创建对象(视为工厂里的产品)时无需指定创建对象的具体类,可以把所有实例化的代码都集中在一个位置

var XMLHttpFactory =function(){};      //这是一个简单工厂模式
  XMLHttpFactory.createXMLHttp =function(){
    var XMLHttp = null;
    if (window.XMLHttpRequest){
      XMLHttp = new XMLHttpRequest()
    }elseif (window.ActiveXObject){
      XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
    }
  return XMLHttp;
  }
  //XMLHttpFactory.createXMLHttp()这个方法根据当前环境的具体情况返回一个XHR对象。

观察者模式

观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者同时监听一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者

var events = (function () {
    var topics = {};
    return {
        publish: function (topic, info) {
            console.log('publish a topic:' + topic);
            if (topics.hasOwnProperty(topic)) {
                topics[topic].forEach(function (handler) {
                    handler(info ? info : {});
                })
            }
        },
        subscribe: function (topic, handler) {
            console.log('subscribe a topic:' + topic);
            if (!topics.hasOwnProperty(topic)) {
                topics[topic] = [];
            }
            topics[topic].push(handler);
        }
    }
})();

//主题监听函数
var handler = function (info) {
    console.log(info);
};
//订阅hello主题
events.subscribe('hello', handler);
//发布hello主题
events.publish('hello', 'hello world');

责任链模式

是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止

DOM里的事件冒泡机制和此类似,比如点击一个按钮以后,如果不阻止冒泡,其click事件将一直向父元素冒泡,利用这个机制也可以处理很多相关的问题

建造者模式可以将一个复杂对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

function getBeerById(id, callback) {
    // 使用ID来请求数据,然后返回数据.
    asyncRequest('GET', 'beer.uri?id=' + id, function (resp) {
        // callback调用 response
        callback(resp.responseText);
    });
}

公钥加密和私钥加密。

公开密钥加密 也称为非对称加密,需要一对密钥,一个是私人密钥,另一个则是公开密钥。这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密钥才能解密。如果知道了其中一个,并不能计算出另外一个。因此如果公开了一对密钥中的一个,并不会危害到另外一个的秘密性质。称公开的密钥为公钥;不公开的密钥为私钥。

RSA是常见的公钥加密算法。

对称密钥加密 又称为私钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。实务上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通讯联系。与公开密钥加密相比,要求双方取得相同的密钥是对称密钥加密的主要缺点之一。

常见的对称加密算法有 DES、3DES、AES

creeperyang/blog#1

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

Asynchronous JavaScript + XML ,无需刷新页面就可以从服务器取得数据的技术。核心是XMLHttpRequest对象。

GET:

var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
  if (request.status >= 200 && request.status < 400) {
    var resp = request.responseText;
  }
};
request.onerror = function() {
};
request.send();

POST:

var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.send(data);

Ajax 解决浏览器缓存问题?

url加上随机数或者时间戳

LINK

200 memory from cache 和 304

200 memory from cache 是不向浏览器发送请求,直接使用本地缓存文件。

304,浏览器虽然发现了本地有该资源的缓存,但是不确定是否是最新的,于是想服务器询问,若服务器认为浏览器的缓存版本还可用,那么便会返回304。

http状态码有那些?分别代表是什么意思?

200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。

403 Forbidden 服务器已经理解请求,但是拒绝执行它。

404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现。

500 Internal Server Error 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。

请你说说 get 和 post的区别

GET 用来获取资源,POST 用来新建资源(也可以用于更新资源),PUT 用来更新资源,DELETE 用来删除资源

GET 相对 POST 的优势是:

请求中的 URL 可以被手动输入;

请求中的 URL 可以被存在书签里,或者历史里;

请求中的 URL 可以被缓存;

HTTP Method Idempotent (幂等的) Safe(安全的)
OPTIONS yes yes
GET yes yes
PUT yes no
POST no no

详见博客理解HTTP协议

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

1.输入地址

2.浏览器查找域名的 IP 地址,这一步包括 DNS 具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存...

3.浏览器向 web 服务器发送一个 HTTP 请求

4.服务器的永久重定向响应(从 http://example.comhttp://www.example.com)

5.浏览器跟踪重定向地址

6.服务器处理请求

7.服务器返回一个 HTTP 响应

8.浏览器显示 HTML

9.浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)

10.浏览器发送异步请求

如何解决跨域问题?

默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源(协议,端口和主机都相同)

CORS

简单请求

只使用 GET, HEAD 或者 POST 数据类型(Content-Type)是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain 中的一种

非简单请求(预请求)

请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。

不同于简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。

//设置跨域访问
app.all('*', function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

JSONP

JSONP利用没有跨域限制的 script 标签加载预设的 callback 将内容传递给 JavaScript

详见博客:CORS 跨域资源共享

CSRF 和 XSS

CSRF(跨站域请求伪造)是一种网络的攻击方式,其原理是攻击者构造接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。

防御CSRF

1.HTTP Referer 字段;

2.在请求地址中添加 token 并验证。CSRF 是因为攻击者可以完全伪造用户的请求,请求中的信息都是存在于 cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。而token可以不存在cookie中。

详见博客:CSRF 与 XSS 攻击

XSS

跨站脚本(XSS)是一种安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

Web 应用未对用户提交请求的数据做充分的检查过滤,允许用户在提交的数据中掺入 HTML 代码(最主要的是>、<),并将未经转义的恶意代码输出到第三方用户的浏览器解释执行,是导致XSS漏洞的产生原因。

防御 XSS 攻击最主要的方法是过滤特殊字符,进行 HTML 转义。

Socket 和 Websocket

1.HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。

在HTTP1.1中加入了持久链接keep-alive
只要任意一端没有明确提出断开连接,则保持TCP连接状态,减少TCP连接和断开的开销。

2.但是一个request只能有一个response。而且这个response是被动的,不能主动发起。

实现实时信息传递:

1.ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息

3.Websocket是基于HTTP协议的,或者说借用了HTTP的协议来完成一部分握手

LazyMan

思路:使用一个队列来维护任务列表,通过返回 this 来实现链式调用,为了在任务队列中先 push 完所有任务然后再依次执行,添加上 setTimeout 函数

function _LazyMan(name) {

    this.tasks = []
    var _this = this

    var fn = (function () {
        console.log(`Hi! This is ${name}!`)
        _this._next()
    })

    this.tasks.push(fn)

    setTimeout(function () {
        _this._next()
    }, 0)
}

_LazyMan.prototype._next = function () {
    var fn = this.tasks.shift()
    fn && fn()
}

_LazyMan.prototype.eat = function (name) {
    var _this = this

    var fn = (function () {
        console.log(`Eat ${name}`)
        _this._next()
    })

    this.tasks.push(fn)
    return this
}

_LazyMan.prototype.sleep = function (time) {
    var _this = this

    var fn = (function () {
        setTimeout(function () {
            console.log(`Wake up after ${time} s`)
            _this._next()
        }, time * 1000)
    })

    this.tasks.push(fn)
    return this
}

_LazyMan.prototype.sleepFirst = function (time) {
    var _this = this

    var fn = (function () {
        setTimeout(function () {
            console.log(`Wake up after ${time} s`)
            _this._next()
        }, time * 1000)
    })

    this.tasks.unshift(fn)
    return this
}

function LazyMan(name) {
    return new _LazyMan(name)
}

LazyMan('GGG').sleep(3).eat('milk').eat('fish').sleep(2).eat('water').sleepFirst(2)

详见博客:如何实现一个LazyMan

数组去重

ES5:

function unique(arr) {
        return arr.filter(function (item, index, array) {
            // indexOf()方法返回给定元素能找在数组中找到的第一个索引值
            return array.indexOf(item) === index;
        });
    }  

ES6:

function unique(arr) {
        return Array.from(new Set(arr));
    }       

数组降维

function flatten(arr) {
     return Array.prototype.concat.apply([], arr);
}  

多维数组

function flatten(arr) {
    var newArr = [];
    for (var i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {  
            newArr.push.apply(newArr, flatten(arr[i]));
        } else {
            newArr.push(arr[i]);
        }
    }
    return newArr;
}    

如何实现数组的随机排序?

function shuffle(a) {
        // concat 复制原数组
        return a.concat().sort(function (a, b) {
            return Math.random() - 0.5;
        });
    }

详见博客:数组乱序

类数组转为数组

Array.prototype.slice.call(fakeArr);

JS是按值传递还是按引用传递?

按值传递(call by value):函数的形参是被调用时所传实参的副本(内存副本)。修改形参的值并不会影响实参。

按引用传递(call by reference):函数的形参接收实参的隐式引用(内存指针),而不再是副本。这意味着函数形参的值如果被修改,实参也会被修改,两者指向相同的值。

JS中的基本类型按值传递,对象类型按共享传递的(call by sharing)。调用函数传参时,函数接受对象实参引用的副本(引用的拷贝)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值

浅复制和深复制

首先深复制和浅复制只针对像Object,Array这样的复杂对象的。

浅复制:复制引用,所有引用对象指向同一数据,只复制一层对象的属性
深复制:递归复制了所有层级

function deepCopy(result, source) {
        for (var key in source) {
            var copy = source[key];
            if (source === copy) continue; // 如window.window === window,会陷入死循环,需要处理一下
            if (Object.prototype.toString.call(copy) === "[object Object]") {
                result[key] = deepCopy(result[key] || {}, copy);
            } else if (Object.prototype.toString.call(copy) === "[object Array]") {
                result[key] = deepCopy(result[key] || [], copy);
            } else {
                result[key] = copy;
            }
        }
        return result;
    }

详见博客:浅复制和深复制

函数式编程

函数即不依赖外部的状态也不修改外部的状态(没有副作用),函数调用的结果不依赖调用的时间和位置,只要给定输入参数,返回的结果必定相同(引用透明),这样写的代码容易进行推理,不容易出错

详见博客:浅谈函数式编程

尾调用

尾调用(Tail Call)是函数式编程里的一个重要概念,它是指某个函数的最后一步是调用另一个函数

function f(x){
  return g(x);
}

用尾递归的方式来优化斐波那契数列,可以避免栈溢出(stack overflow)

function fibonacci (n , a = 0 , b = 1) {
  if( n === 0 ) {return a};

  return fibonacci (n - 1, b, a + b);
}    

详见博客:JavaScript 中的尾调用

单元测试

单元测试关注的是验证一个模块或一段代码的执行效果是否和设计或预期一样。

mocha 摩卡
chai

  describe('$.type()', function () {
        it("string", function () {
            $.type('string').should.equal('string');

        });
  });      

Java和JavaScript对比

  • JavaScript 是动态类型语言,而 Java 是静态类型语言;

动态类型语言:动态类型语言是指在运行期间才去做数据类型检查的语言
静态类型语言:静态类型语言与动态类型语言刚好相反,它的数据类型是在编译期间检查的,也就是说在写程序时要声明所有变量的数据类型

  • JavaScript 是弱类型的,Java 属于强类型;
  • JavaScript 的面向对象是基于原型的(prototype-based)实现的,Java 是基于类(class-based)的;
  • Java 创建在虚拟机或浏览器中运行的应用程序,而 JavaScript 代码仅在浏览器中运行。
  • Java 代码需要进行编译,而 JavaScript 代码都在文本中。

webpack和gulp对比

  • Gulp / Grunt 是一种工具,能够优化前端工作流程。比如自动刷新页面、combo、压缩css、js、编译less等等。简单来说,就是使用Gulp/Grunt,然后配置你需要的插件,就可以把以前需要手工做的事情让它帮你做了。
  • seajs / require : 是一种在线编译"模块的方案,相当于在页面上加载一个 CMD/AMD 解释器。这样浏览器就认识了 define、exports、module 这些东西。也就实现了模块化。
  • browserify / webpack : 是一个预编译模块的方案,相比于上面 ,这个方案更加智能。没用过browserify,这里以webpack为例。首先,它是预编译的,不需要在浏览器中加载解释器。另外,你在本地直接写JS,不管是 AMD / CMD / ES6 风格的模块化,它都能认识,并且编译成浏览器认识的JS。

http://www.jianshu.com/p/42e11515c10f

Promise

为了解决callback hell,

所谓 Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise 对象代表一个异步操作有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

new Promise((resolve, reject) => {
    setTimeout(resolve('done'), 100);
}).then(value =>
    console.log(value)
).catch(error =>
    console.log(error)
);

RxJS

RxJS 是用来解决异步和事件组合问题

Observable = 异步数组 = 数组 + 时间轴 = stream

const Observable = Rx.Observable
const input = document.querySelector('input')

const search$ = Observable.fromEvent(input, 'input')
    .map(e => e.target.value)
    .filter(value => value.length >= 1)
    // .throttleTime(200) // 节流事件,指的是该事件最多每几秒触发一次
    .debounceTime(200) //去抖动时间,指的是必须等待的时间
    .distinctUntilChanged()// 当我们观察的数据状态发生改变的时候才会释放数据
    .switchMap(term => Observable.fromPromise(wikiIt(term)))
    .subscribe(
        x => render(x),
        err => console.error(err)
    )

function render(result) {
    document.querySelector('#result').innerHTML = result[1]
        .map(r => `<li>${r}</li>`)
        .join('')
}

function wikiIt(term) {
    console.log('request...')
    var url = 'https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=' + encodeURIComponent(term) + '&origin=*';
    return $.getJSON(url)
}

Async + Await

async函数是 Generator 函数的语法糖,返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

async function run() {
    const articles = await getArticleList();
    const article = await getArticle(articles[0].id);
    return await getAuthor(article.authorId)
}

run().then((author) => alert(author.email))
    .catch((error) => console.error(error))

function getAuthor(id) {
    return new Promise((resolve, reject) => {
        $.ajax("http://beta.json-generator.com/api/json/get/E105pDLh", {author: id})
            .done((result) => resolve(result))
    })
}

function getArticle(id) {
    return new Promise((resolve, reject) => {
        $.ajax("http://beta.json-generator.com/api/json/get/EkI02vUn", {id: id})
            .done((result) => resolve(result))
            .fail((jqXHR, textStatus, errorThrown) => reject(textStatus))
    })
}

function getArticleList() {
    return new Promise((resolve, reject) => {
        $.ajax("http://beta.json-generator.com/api/json/get/Ey8JqwIh")
            .done((result) => resolve(result));
    })
}

对比

可以看出 RxJS 对于这类数据可以做一种类似流式的处理,也是非常优雅,而且 RxJS 强大之处在于你还可以对数据做取消、监听、节流等等的操作

Observable Object 中有 toPromise 方法,可以返回一个 Promise Object,同样可以结合 await 使用。当然你也可以只使用 async/await 配合 underscore 或者其他库,也能实现很优雅的效果。总之,RxJS 与 async/await 不冲突。

TypeScript

TypeScript 是 JavaScript 的强类型版本。然后在编译期去掉类型和特有语法,生成纯粹的 JavaScript 代码。TypeScript 并不依赖于浏览器的支持,也并不会带来兼容性问题

TypeScript 是 JavaScript 的超集

优点

静态类型检查,编译器发现错误;

IDE智能提示;

可读性;

declare var $: any;

$.get('/') // => ok

d.ts 文件来标记某个 js 库里面对象的类型
typings 就是一个网络上的 d.ts 数据库

Vue2原理,Angular2原理 ?

Vue 中如果对象属性的添加或删除无法被检测到,那么你有什么解决方案?

受现代 JavaScript 的限制(以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。

Vue.set(vm.someObject, 'b', 2)

Underscore和Zepto源码

1.Object.prototype.toString.call() 判断类型

2.函数去抖与函数节流

函数去抖就是对于一定时间内的连续的函数调用,只让其执行一次。核心思想是重复添加定时器。

函数节流是指一个函数在一定间隔内调用,目的是让一个函数不要执行得太频繁。

3.函数记忆

原理非常简单,就是把函数的每次执行结果都放入一个散列表中,在接下来的执行中,在散列表中查找,如果有,直接返回该值,没有才执行函数。

    var memoize = function (func) {
        var cache = {};
        return function (key) {
            if (!cache[key])
                cache[key] = func.apply(this, arguments);
            return cache[key];
        }
    }

    var fibonacci = memoize(function (n) {
        return n < 2 ? n : fibonacci(n - 2) + fibonacci(n - 1);
    });

详见博客:Underscore.js 源码学习笔记

柯里化与偏函数

函数柯里化的本质是,可以在调用一个函数的时候传入更少的参数,而这个函数会返回另外一个函数并且能够接收其他参数。是一种实现多参数函数的方法。

function add(x){
    return function(y){
        return x + y;
    }
}
var inc = add(1)
var dev = add(-1)
inc(1) // 2
dev(1) // 0

偏函数应用到了 bind ,他解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

前端性能优化的方法(JS/CSS)?

1.减少/最小化 http 请求数
2.延迟加载组件
3.使用CDN
4.加Expires或者Cache-Control头部
5.传输时用gzip等压缩组件
6.把样式放在顶部
7.把脚本放到底部
8.压缩JS和CSS

Vue 和 Angular 区别 如何选择?

JavaScript有什么吸引你的地方?

1.单线程事件轮询是个很适合异步并发的模型,因为避免了在程序内部管理多个线程带来的各种问题。

2.函数作为一等公民存在(通过字面量创建,可以作为参数传递),闭包,函数式风格。

3.灵活。duck typing,动态指定函数的执行语境,动态修改原型,动态修改原型链,甚至修改原生对象的原型...

鸭子类型(duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。

function foo() {
    var args = Array.prototype.slice.call(arguments);
    //...
}

arguments不是Array类型,因此它没有slice方法,但是arguments对象满足了slice方法的一些条件:

  • 有一个length属性,它的值是数值
  • 通过0 ~ length索引这个对象都有值

因此,arguments可以应用于slice方法,于是我们也可以这样用:

JavaScript面向对象编程?

在JavaScript中,命名空间只是另一个包含方法,属性,对象的对象。

var MYAPP = MYAPP || {};

JavaScript是一种基于原型的语言,它没类的声明语句,比如C+ +或Java中用的。这有时会对习惯使用有类申明语句语言的程序员产生困扰。相反,JavaScript可用方法作类。定义一个类跟定义一个函数一样简单。在下面的例子中,我们定义了一个新类Person。

function Person() { } 
// 或
var Person = function(){ }

Event Loop

主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop

不可变对象

number,string

项目中遇到的最大的问题,你是如何解决的?

你知道哪些知名的博客主?

@bigggge bigggge modified the milestone: javascript May 18, 2017
@bigggge bigggge added the JS label Jul 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant