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,放大鏡可重用的模塊

相關文章
相關標籤/搜索