JavaScript试题(二)

 Javascript的typeof返回哪些数据类型;列举3种强制类型转换和2中隐式类型转换前端

1)返回数据类型android

undefined string boolean number symbol(ES6) Object Functiones6

2)强制类型转换web

Number(参数)  把任何类型转换成数值类型。parseInt(参数1,参数2)  将字符串转换成整数 parseFloat()将字符串转换成浮点数字chrome

string(参数):能够将任何类型转换成字符串 Boolean()  能够将任何类型的值转换成布尔值。npm

3)隐式类型转换json

1.四则运算windows

加法运算符+是双目运算符,只要其中一个是String类型,表达式的值即是一个String。api

对于其余的四则运算,只有其中一个是Number类型,表达式的值即是一个Number。数组

对于非法字符的状况一般会返回NaN:

'1' * 'a'     // => NaN,这是由于parseInt(a)值为NaN,1 * NaN 仍是 NaN

2.判断语句

判断语句中的判断条件须要是Boolean类型,因此条件表达式会被隐式转换为Boolean。   其转换规则同Boolean的构造函数。好比:

var obj = {};if(obj){

    while(obj);}

3.Native代码调用

JavaScript宿主环境都会提供大量的对象,它们每每很多经过JavaScript来实现的。  JavaScript给这些函数传入的参数也会进行隐式转换。例如BOM提供的alert方法接受String类型的参数:

alert({a: 1});    // => [object Object]

ES6的箭头函数和普通的function有什么区别?

this指针不一样。
function的this指向调用对象。----运行时指针
箭头函数的this指向不变,声明时的环境。----声明时指针

箭头函数的使用限制:不能做为构造函数,不能经过call, apply, bind来修正指针。

箭头函数没有arguments

1、 写出3个使用this的典型应用

1.

function Thing() { }

 Thing.prototype.foo = "bar";

 Thing.prototype.logFoo = function () {

      console.log(this.foo);

 }

 Thing.prototype.setFoo = function (newFoo) {

      this.foo = newFoo;

  }

  var thing1 = new Thing();

  var thing2 = new Thing();

 thing1.logFoo(); //logs "bar"

 thing2.logFoo(); //logs "bar"

 thing1.setFoo("foo");

 thing1.logFoo(); //logs "foo";

 thing2.logFoo(); //logs "bar";

 thing2.foo = "foobar";

 thing1.logFoo(); //logs "foo";

 thing2.logFoo(); //logs "foobar";
View Code

2.

function Thing1() { }

  Thing1.prototype.foo = "bar";

  function Thing2() {

     this.foo = "foo";

 }

  Thing2.prototype = new Thing1();

  function Thing3() {}

  Thing3.prototype = new Thing2();

  var thing = new Thing3();

  console.log(thing.foo); //logs "foo"
View Code

3.

function Thing() {}

  Thing.prototype.foo = "bar";

  Thing.prototype.logFoo = function () {

      function doIt() {

          onsole.log(this.foo);

       }

      doIt.apply(this);

  }

 function doItIndirectly(method) {

method();

 }

var thing = new Thing();

doItIndirectly(thing.logFoo.bind(thing)); //logs bar
View Code

  Eval函数的做用

   eval能够将字符串生成语句执行,通常执行动态的js语句。
   eval的使用场合:有时候咱们预先不知道要执行什么语句,只有当条件和参数给时才知道执行什么语句,这时候eval就派上用场了。

 如何将一个元素600毫秒的速度缓慢向上滑动显示?

若是须要在父元素底部向上,能够利用margin一top 把子元素,挤下去,同事父元素设置隐藏,而后改变margintop的值也能够利用定来作,把子元素定位最下边

(function(){
        var oDiv = document.createElement('div');
        oDiv.style.width = '100px';
        oDiv.style.height = '100px';
        oDiv.style.backgroundColor = 'red';
        oDiv.style.position = 'absolute';
        oDiv.style.marginTop = 100 + 'px';
        document.body.appendChild(oDiv);
        var timer = setInterval(function(){
            var m = parseInt(oDiv.style.marginTop);
            if (m == 0 ) {
                clearInterval(timer);
                return;
            }
            oDiv.style.marginTop = parseInt(oDiv.style.marginTop) 一 1 + 'px';
        },600);
    })();
View Code

 你如何从浏览器的URL中获取参数信息(重要)

浏览器宿主环境中,有一个location对象,同时这个对象也是window对象和document对象的属性。

location对象中提供了与当前窗口加载的文档有关的的信息,即URL信息。

  如  https://www.baidu.com/api/sousu?search=baidu&id=123#2

         location.href: 完整URL

         location.protocol: 返回协议(https:)

         location.host: 返回服务器名称和端口号(www.baidu.com

 location.hostname: 返回服务器名称(www.baidu.com

 location.port:返回服务器端口号(http默认80,https默认443)

 location.pathname:返回URL中的目录和文件名(api/sousu)

 location.search:返回查询字符串(?search=baidu&id=123#2)

 location.hash:返回hash值(#2)

 Javascript同源策略

同源策略是Javascript重要的安全度量标准。它最先出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不一样源装载。所谓的同源就是同协议,同主机名,同端口号。

它的精髓很简单:它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被容许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

为何要有同源限制?

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

缺点:

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

  懒加载的实现原理?

意义:懒加载的主要目的是做为服务器前端的优化,减小请求数或延迟请求数。

实现原理:先加载一部分数据,当触发某个条件时利用异步加载剩余的数据,新获得的数据 不会影响原有数据的显示,同时最大程度上减小服务器端的资源耗用。

实现方式:

  1. 第一种是纯粹的延迟加载,使用setTimeOut或setlnterval进行加载延迟.
  2. 第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。
  3. 第三种是可视区加载,即仅加载用户能够看到的区域,这个主要由监控滚动条来实现,通常会在距用户看到某图片前必定距离便开始加载,这样能保证用户拉下时正好能看到图片。

如:

<img id="banner1" data-url="http://www.cnblogs.com/fanlinqiang/">

... ...// 当条件知足时
var el = document.getElementById('banner1')
el.setAttribute('src', el.dataset.url)

 怎么实现一个相似于const功能的方法?

es6中const至关于声明常量不可更改,咱们利用defineProperty能够模拟实现;咱们把 writable设置为false的时候,该属性就成了只读,也就知足了常量了性质,咱们把常量封装 在CONST命名空间里面,可是由于咱们依然能够经过修改属性writable为true修改属性值,因此 configurable设置为false,不能修改属性;

模拟:以下代码CONST.a至关于es6中cont a=2; CONST.a是不能够更改的常量;

var CONST = { };
Object.defineProperty(CONST, ‘a’, { 
    value: 2,
    writable: false,  //可写
    configurable: false, // 可删除
    enumerable: true //可枚举 
});    
console.log(CONST.a);    //2
CONST.a = 3;
console.log(CONST.a);    //2

 Apply和call方法的异同

相同点:两个方法产生的做用是彻底同样的,第一个参数都是对象;

不一样点:

call()方法参数将依次传递给借用的方法做参数,即fn.call(thisobj, arg1,arg2,arg3...argn),有n个参数

apply()方法第一个参数是对象,第二个参数是数组fn.apply(thisobj,arg),此处的arg是一个数组,只有两个参数

使用原生js模拟一个apply方法

apply方法:

语法:apply([thisObj[,argArray]])

定义:应用某一对象的一个方法,用另外一个对象替换当前对象。

说明:

若是 argArray 不是一个有效的数组或者不是 arguments 对象,那么将致使一个 TypeError。

若是没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用做 thisObj, 而且没法被传递任何参数。

Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;
    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }
    delete context.fn
    return result;
}
View Code

  使用原生js模拟一个call方法

call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。

Function.prototype.call = function (context) {

    var context = context || window;

    context.fn = this;

    var args = [];

    for(var i = 1, len = arguments.length; i < len; i++) {

        args.push('arguments[' + i + ']');

    }

    var result = eval('context.fn(' + args +')');

    delete context.fn

    return result;

}
View Code

以上两个方法的具体实现原理能够参考:http://www.javashuo.com/article/p-cytaaewc-h.html 

    Object.create()和直接建立对象有什么区别?

Object.create()方法建立一个拥有指定原型和若干个指定属性的对象 //Object.create(proto,[propertiesObject])

该方法建立一个对象,其接受两个参数,第一个参数是这个对象的原型对象proto,

第二个是一个可选参数,用以对对象的属性作进一步描述

若是proto参数不是null或一个对象值,则抛出一个TypeError异常

var objl = Object.create({

     x: 1,

     y: 2

}); //对象obj1继承了属性x和y

var obj2 = Object.create(null);//对象 obj2 没有原型

对象字面量是建立对象最简单的一种形式,

目的是在于简化建立包含大量属性的对象的过程。

对象字面量由若干属性名(keys)和属性值(values)成对组成的映射表,

key和value中间使用冒号(:)分隔,

每对key/value之间使用逗号(,)分隔,

整个映射表用花括号({})括起来。

在用字面量来建立对象的时候,对象中的property定义能够用单引号或双引号来包括,也能够忽略引号。不过,当property中出现空格、斜杠等特殊字符,或者使用的property与JS关键词冲突时,则必须使用引号。

var obj = {

property_1: value_1,// property—# 多是一个标识符...

2: value_2, //或者是一个数字 "property n": value_n // 或是一个字符串

}

经过对象字面量建立的对象复用性较差,

使用Object.create()建立对象时不须要定义一个构造函数就容许你在对象中选择其原型对象。

 使用for in遍历对象和使用Object.keys来遍历对象 有什么区别?

1.for in主要用于遍历对象的可枚举属性,包括自有属性、继承自原型的属性

2.Object.keys返回一个数组,元素均为对象自有的可枚举属性

3.Object.getOwnProperty 用于返回对象的自有属性,包括可枚举的和不可枚举的

var obj = {

    "name":"xiaosan",

    "age":23

}

Object.defineProperty(obj,"height",{value:178,enumerable:false})

Object.prototype.prototypel = function(){

    console.log('aaa')

}

Object.prototype.prototype2 = 'bbb';

//for in

for(var i in obj){

    console.log(i); //name age prototypel prototype2

}

//Object.keys

console.log(Object.keys(obj)) //name age

//Object.getOwnProperty

console.log(Object.getOwnPropertyNames(obj)) //name age height
View Code

 深拷贝和浅拷贝以及应用场景

i.浅拷贝

//拷贝就是把父对象的属性,所有拷贝给子对象。

var Chinese = {

    nation:'中国’

}

Var Doctor={

    career:'医生'

}

function extendCopy(p) {

    var c = {};

    for (var i in p) {

        c[i] = p[i];

    }

    c.uber = p; return c;

}

//使用的时候,这样写:

Doctor = extendCopy(Chinese);

Doctor.career ='医生';

alert(Doctor.nation); // 中国    
View Code

//可是,这样的拷贝有一个问题。那就是,若是父对象的属性等于数组或另外一个对象,那么实际上,子对象得到的只是一个内存地址,而不是真正拷贝,所以存在父对象被篡改的可能。

//请看,如今给Chinese添加一个"出生地"属性,它的值是一个数组。

Chinese.birthPlaces =['北京','上海','香港'];

//经过extendCopy()函数,Doctor继承了Chinese。

Doctor = extendCopy(Chinese);

//而后,咱们为Doctor的"出生地"添加一个城市:

Doctor.birthPlaces.push('厦门');

//看一下输入结果

alert(Doctor.birthPlaces); //北京,上海,香港,厦门 alert(Chinese.birthPlaces); //北京,上海,香港,厦门

//结果是两个的出生地都被改了。

//因此,extendCopy()只是拷贝了基本类型的数据,咱们把这种拷贝叫作''浅拷贝〃。

浅拷贝的实现方式还有:

Jquery:jQuery.merge(first,second)

概述合并两个数组,返回的结果会修改第一个数组的内容——第一个数组的元素后面跟着第二个数组的元素。要去除重复项,请使用$.unique()

用法:$.merge( first , second ),

first:第一个待处理数组,会改变其中的元素。second:第二个待处理数组,不会改变其中的元素。

$.merge( [0,1,2], [2,3,4] )

es6中assign,详见:http://es6.ruanyifeng.com/?search=assign&x=0&y=0#docs/object#Object-assign

Object.assign方法用于对象的合并,将源对象(source)的全部可枚举属性,复制到目标对象(target)。

语法:Object.assign(target , source1, source2, ...)

tips:Object.assign拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)。

es6展开操做符...

var state = [
    {
     a:1, b:function(){} } ] var tmp =[...state]  

2.深拷贝

//所谓"深拷贝",就是可以实现真正意义上的数组和对象的拷贝。它的实现并不难, 只要递归调用"浅拷贝"就好了。

var Chinese = {

    nation:'中国’

}

var Doctor = {

    career:'医生'

}

function deepCopy(p, c) {

    var c = c || {};

for (var i in p) {

    if (typeof p[i] === 'object') {

    c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]);

} else {

    c[i] = p[i];

}

}

    return c;

}

//看一下使用方法:

Doctor = deepCopy(Chinese);
View Code

//如今,给父对象加一个属性,值为数组。而后,在子对象上修改这个属性:

Chinese.birthPlaces =['北京','上海','香港'];

Doctor.birthPlaces.push('厦门');

alert(Doctor.birthPlaces); //北京,上海,香港,厦门

alert(Chinese.birthPlaces); //北京,上海,香港

JavaScript中的对象通常是可变的(Mutable),由于使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如'foo={a: 1}; bar=foo; bar.a=2'你会发现此时 'foo.a'也被改为了 '2'。

虽然这样作能够节约内存,但当应用复杂后,这就形成了很是大的隐患,Mutable带来的优势变得得不偿失。为了解决这个问题,通常的作法是使用shallowCopy (浅拷贝)或deepCopy (深拷贝)来避免被修改,但这样作形成了CPU和内存的浪费。

Immutable能够很好地解决这些问题。

jQuery.extend()

.jQuery.extend( [deep ], target, object1 [, objectN ] ),其中deep为Boolean类型,若是是true,则进行深拷贝。

var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = $.extend(true, target, copy1, copy2);   // 进行深拷贝
console.log(target);    // {a: 2, b: 2, c: {ca: 31, cb: 32, cc: 23, cd: 34}}
var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = $.extend(target, copy1, copy2);   // 不进行深拷贝
console.log(target);    // {a: 1, b: 1, c: {ca: 31, cb: 32, cd:34}}

经过上面的对比能够看出,当使用extend()进行深拷贝的时候,对象的全部属性都添加到target中了。

使用JSON.parse()和JSON.stringify()

var target = {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}};
var targetCopy = JSON.parse(JSON.stringify(target));
targetCopy.a = 2;
targetCopy.c.ca = 21;
console.log(target);   // {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}}
console.log(targetCopy);    // {a: 2, b: 1, c: {ca: 21, cb: 12, cc: 13}}
console.log(target === targetCopy);  // false

JSON.parse()和JSON.stringify()能正确处理的对象只有Number、String、Array等可以被json表示的数据结构,所以函数这种不能被json表示的类型将不能被正确处理。

1、 原型链,闭包与继承

闭包的好处:

1.不会污染全局环境;

2.能够进行形参的记忆,减小形参的个数,延长形参生命周期;

function add(x) {
    return function(y) {
        return (x+y);
    }
}

var sum = add(2);

sum(5);//结果为 7

3.方便进行模块化开发;

var module = (function() {
    var name = '123';
    function init() {
        console.log(name);
    }
    return {
        getname:init
    }

})()

module.getname();//结果为 123;    
View Code

继承:一个构造函数继承另外一个构造函数中的方法;能够省去大量的重复。

function Man(name,age) {

    this.name = name; this.age = age;

}

var person = new Man('tom',19);

function Woman(name,age) {

    this.sex = 'woman';

    Man.call(this,name,age);

}

Woman.prototype = Man.prototype;

var person1 = new Woman('july',20);

person1.name//结果为 july

person1.age //结果为 20

person1.sex //结果为 woman
View Code

原型链查找:进行方法调用的时候,会先在实例自身上找,若是没有就去该实例的原型上找。

function People() {

    this.name = 'a People';

}

People.prototype.say = function() {

    this.age = '10';

    console.log(this.name,this.age);

}

var person = new People();

person.say();
View Code

 判断当前浏览器的类型及版本?

function checkBrower() {
    var Sys = {};
    var ua = navigator.userAgent.toLowerCase();
    if (window.ActiveXObject) {
        Sys.ie = ua.match(/msie ([\d.]+)/)[1];
        //获取版本
        var ie_version = 6;
        if (Sys.ie.indexOf("7") > -1) {
            ie_version = 7;
        }
        if (Sys.ie.indexOf("8") > -1) {
            ie_version = 8;
        }
        if (Sys.ie.indexOf("9") > -1) {
            ie_version = 9;
        }
        if (Sys.ie.indexOf("10") > -1) {
            ie_version = 10;
        }
        if (Sys.ie.indexOf("11") > -1) {
            ie_version = 11;
        }
    }
    else if (ua.indexOf("firefox") > -1)
        Sys.firefox = ua.match(/firefox\/([\d.]+)/)[1];
    else if (ua.indexOf("chrome") > -1)
        Sys.chrome = ua.match(/chrome\/([\d.]+)/)[1];
    else if (window.opera)
        Sys.opera = ua.match(/opera.([\d.]+)/)[1];
    else if (window.openDatabase)
        Sys.safari = ua.match(/version\/([\d.]+)/)[1];

    return Sys;
}

 js判断用户的浏览器设备是移动端仍是pc端

        function browserRedirect() {
            var sUserAgent = navigator.userAgent.toLowerCase();
            var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
            var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
            var bIsMidp = sUserAgent.match(/midp/i) == "midp";
            var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
            var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
            var bIsAndroid = sUserAgent.match(/android/i) == "android";
            var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
            var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
            document.writeln("您的浏览设备为:");
            if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
                document.writeln("phone");
            } else {
                document.writeln("pc");
            }
        }

        browserRedirect();

 

判断是否微信浏览器中打开

function is_weixn(){  
    var ua = navigator.userAgent.toLowerCase();  
    if(ua.match(/MicroMessenger/i)=="micromessenger") {  
        return true;  
    } else {  
        return false;  
    }  
}  

 

比较两个对象是否相等(非引用地址的比较)?

https://www.npmjs.com/package/deep-equal

箭头函数与普通函数的区别?

箭头函数做为匿名函数,是不能做为构造函数的,不能使用new
箭头函数不绑定arguments,取而代之用rest参数…解决
箭头函数会捕获其所在上下文的 this 值,做为本身的 this 值
箭头函数没有原型属性
箭头函数不能当作Generator函数,不能使用yield关键字
箭头函数的this永远指向其上下文的 this,不可以被修正,如call(), bind(), apply()

详见:http://www.jianshu.com/p/73cbeb6782a0

 ES6里面你用过什么?

1) 块做用域一let

2) 常亮一const

3) 解构数组一Array Destructuring:

View Code

4) 解构对象一Object Destructuring

5) 模板字符串一Template Strings

6) 展开操做符

7) 剩余操做符

8) 解构参数

9) 箭头函数

10)        对象表达式

11)        对象属性名

12)        对比两个值是否相等

13)        把对象的值复制到另外一个对象里,Object.assign( {}, obj1, obj2 )

14)        设置对象的prototype

15)        __proto__

16)        supper

17)        迭代器

18)         class 类

19)        get set

20)        静态方法

21)        继承

22)        模块化

细节参见:http://es6.ruanyifeng.com/

说说你对面向对象的理解?

面向对象,分工协做可复用

面向对象:banner,放大镜可重用的模块

相关文章
相关标签/搜索