javascript 技術精要

圖靈大盜發表於2018-03-22

空陣列與布林值的比較

// 先執行[].toString() => "" ,!"" => true;  現在變為: [] == true => 最後結構就是true;

[] == ![]  


複製程式碼
[] == false
/***
 引用資料型別與布林型別比較,先將 引用資料型別轉化為 基本資料型別
 [].toString() => "" => "" == false ==>比較結果就是true
 ***/

// js中的坑
1===1 ===1 // => false

true === (1===1) // => true
複製程式碼

去掉小數部分 ~~

~是按位取反運算,~~是取反兩次
在這裡~~的作用是去掉小數部分
因為位運算的操作值要求是整數,其結果也是整數,所以經過位運算的都會自動變成整數
除了~~n 還可以用
n<<0
n>>0
n|0
取整
與Math.floor()不同的是,它只是單純的去掉小數部分,不論正負都不會改變整數部分
複製程式碼

解釋下 null 與 undefined 的區別

  • null 是一個==空指標物件==,是一個可以被分配的值,設定為 null 的變數意味著其==無值==。所以 typeof null => "object"
  • undefined 則代表著某個變數雖然宣告瞭但是==尚未進行過任何賦值==。

淺拷貝

function copy(p){
  var c = {};
  for(var i in p){
   c[i]= p[i]
  }
  c.uber = p

  return c;
 }
複製程式碼

深拷貝

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
}
複製程式碼

常用的繼承方式

  1. 僅從原型繼承 prototype
function Animal(){
 this.home = '我屬於動物園'
}

Animal.prototype.speak = function(){
 console.log(this.home)
}

function Dog(){

}

// 原型繼承
//繼承來自父級的prototype屬性

Dog.prototype = Animal.prototype;
Dog.prototype.constructor = Dog;

var yellowDog = new Dog();

yellowDog.speak()

複製程式碼
  1. 原型鏈繼承(仿傳統)
function Animal(){
 this.home = '我屬於動物園'
}

Animal.prototype.speak = function(){
 console.log(this.home)
}

function Dog(){
  //this.home = 'wawa'
}

// 原型繼承
//繼承來自父級的例項中,這種繼承會繼承父級的 <私有屬性>

Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;

var yellowDog = new Dog();

yellowDog.speak()

複製程式碼
  1. 借用建構函式法

function Animal(name,color){
    this.name = name;
    this.color = color;
}

Animal.prototype.speak = function(){
  console.log('這是'+this.name+',毛色是'+this.color)
}

function Dog(){
  Animal.apply(this,arguments) // 只能繼承父級的私有屬性。
}

var dog1 = new Dog('大黃',2)

複製程式碼
  1. 臨時構造器法
 function extends(Child,Parent){
   // 1.建立一個臨時的建構函式 F
   var F = function(){}
   // 2.臨時建構函式F的原型 => 繼承父級的原型prototype
   F.prototype = Parent.prototype;
   // 3. 子級的原型 => 繼承 臨時建構函式F 的例項
   Child.prototype = new F();
   // 4. 重置子級原型的建構函式
   Child.prototype.constructor = Child;

   // 在子級中新增一個屬性 uber => 儲存 一個父級原型的副本
   Child.uber = Parent.prototype;
 }

複製程式碼

  1. 使用Object.create()

簡單來講,new Object()是一種通過建構函式來建立object的方式,而Object.create(proto, [ propertiesObject ]) 不需要通過建構函式就可以建立一個object,Object.create()的第一個引數是必須要的,第二個引數可選。其實Object.create()內部依然是通過new一個建構函式的方式來實現的,它有建構函式,不過這個建構函式是隱式存在的,看一下使老舊瀏覽器支援Object.create方法的“polyfill”就可以對它們之間的區別一目瞭然了:

if (!Object.create) {
    Object.create = function (o) {
    function F() {}  //定義了一個隱式的建構函式
    F.prototype = o;
    return new F();  //其實還是通過new來實現的
    };
  }
複製程式碼
    function Car (desc) {
        this.desc = desc;
        this.color = "red";
    }

    Car.prototype = {
        getInfo: function() {
          return 'A ' + this.color + ' ' + this.desc + '.';
        }
    };
    //instantiate object using the constructor function
    var car =  Object.create(Car.prototype);
    car.color = "blue";
    alert(car.getInfo());
複製程式碼

XSS原理及防範

==Xss==(cross-site scripting)攻擊指的是攻擊者往Web頁面裡插入惡意html標籤或者javascript程式碼。比如:攻擊者在論壇中放一個 看似安全的連結,騙取使用者點選後,竊取cookie中的使用者私密資訊;或者攻擊者在論壇中加一個惡意表單, 當使用者提交表單的時候,卻把資訊傳送到攻擊者的伺服器中,而不是使用者原本以為的信任站點。

XSS防範方法

1.程式碼裡對==使用者輸入的地方和變數都需要仔細檢查長度和對”<”,”>”,”;”,”’”等字元做過濾==;其次任何內容寫到頁面之前都必須加以encode,避免不小心把html tag 弄出來。這一個層面做好,至少可以堵住超過一半的XSS 攻擊。

2.避免直接在cookie 中洩露使用者隱私,例如email、密碼等等。

3.通過==使cookie 和系統ip 繫結==來降低cookie 洩露後的危險。這樣攻擊者得到的cookie 沒有實際價值,不可能拿來重放。

4.儘量==採用POST== 而非GET 提交表單

new操作符具體幹了什麼呢

1、建立一個空物件,並且 this 變數引用該物件,同時還繼承了該函式的原型。

2、屬性和方法被加入到 this 引用的物件中。

3、新建立的物件由 this 所引用,並且最後隱式的返回 this 。

var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
複製程式碼

陣列快速排序演算法

相關文章

(1)在資料集之中,選擇一個元素作為"基準"(pivot)。

(2)所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。

(3)對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到所有子集只剩下一個元素為止。

  

取陣列中間的值當做參考值,並且把它從原陣列中用splice方法擷取  

function quickSort(arr){
  arr = arr || [];
  if(arr.length <= 1) return arr;
  var midIndex = Math.floor(arr.length/2)
  var midVal = arr.splice(midIndex,1)[0];

  var leftArr = [];
  var rightArr = [];

  for(var i=0;i<arr.length;i++){
	if(arr[i]<midVal){
    	leftArr.push(arr[i])
    }else{
		rightArr.push(arr[i])
    }
  }

  return quickSort(leftArr).concat(midVal,quickSort(rightArr))
}

複製程式碼

將陣列的第一個元素當做參考值,for迴圈從1開始

var a = [2,4,5,63,4,5,63,2,4,43];

function quicksort(arr)
{
    if (arr.length == 0)
        return [];

    var left = new Array();
    var right = new Array();
    var pivot = arr[0];

    for (var i = 1; i < arr.length; i++) {
        if (arr[i] < pivot) {
           left.push(arr[i]);
        } else {
           right.push(arr[i]);
        }
    }

    return quicksort(left).concat(pivot, quicksort(right));
}

console.log(quicksort(a));
複製程式碼

氣泡排序

function bubbleSort(array) {
    if (Object.prototype.toString.call(array).slice(8, -1) === 'Array') {
        var len = array.length,
            temp;
        for (var i = 0; i < len - 1; i++) {
            for (var j = len - 1; j >= i; j--) {
                if (array[j] < array[j - 1]) {
                    temp = array[j];
                    array[j] = array[j - 1];
                    array[j - 1] = temp;
                }
            }
        }
        return array;
    } else {
        return 'array is not an Array!';
    }
}
複製程式碼
function bubbleSort(arr){
  for(var i=0;i<arr.length-1;i++){
    for(var j=i+1;j<arr.length;j++){
      if(arr[i]>arr[j]){
         var temp
         temp = arr[i];
         arr[i]=arr[j];
         arr[j] = temp
       }
    }
  }
  return arr;
}

複製程式碼

一張圖理解prototype、proto和constructor的三角關係

參考 prototype、proto和constructor的三角關係

閉包

function f1(){
&emsp;&emsp;&emsp;&emsp;n=999;
&emsp;&emsp;&emsp;&emsp;function f2(){
&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;alert(n);
&emsp;&emsp;&emsp;&emsp;}
&emsp;&emsp;&emsp;&emsp;return f2;
&emsp;&emsp;}
&emsp;&emsp;var result=f1();
&emsp;&emsp;result(); // 999
&emsp;&emsp;
複製程式碼

各種專業文獻上的“閉包”(closure)定義非常抽象,很難看懂。我的理解是,閉包就是能夠讀取其他函式內部變數的函式。 由於在Javascript語言中,只有函式內部的子函式才能讀取區域性變數,因此可以把閉包簡單理解成“定義在一個函式內部的函式”。 所以,在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑。

  • 它的最大用處有兩個,一個是前面提到的可以讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。
  1. 由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。
  2. 閉包會在父函式外部,改變父函式內部變數的值。所以,如果你把父函式當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便 改變父函式內部變數的值。

關於原型的幾點

1.所有的物件都有prototype 和 __proto__屬性 。 2.所有的建構函式(原生的如Object Function Date 等以及自己宣告的建構函式)都是物件,因此,他們都包含prototype和__proto__屬性

Function.__proto__ === Function.prototype === Object.__proto__
複製程式碼

從上面程式碼可以看出,Object是通過Function 構造出的。

1.所有的普通函式都是通過new Function生成的,所以,每一個函式都是Function的例項。

function fn(){}

fn.__proto__ === Function.prototype  

複製程式碼
function fn1(){
    console.log(1)
}

Function.prototype.call.call(fn1)  //相當於fn1執行。
Function.prototype.call.call.call.call(fn1)  //相當於fn1執行。
複製程式碼

柯理化函式

可以簡單的理解為函式中返回函式的形式。

function fnc(){
    return fn(){

    }
}
複製程式碼
//例項 bind this

function bindThis(bindObj,fn){

    return function(){
        //將類陣列轉化為陣列
        // var arg = [].slice(arguments,0)
        var arg = Array.prototype.slice(arguments,0)

        fn.apply(bindObj,arg)
    }
}

//在原型上新增bind

if(!Function.prototype.bind){

    Function.prototype.bind = function(obj){
        var args = [].slice.call(arguments,1)
        return function(){
            var innerArgs = [].slice.call(arguments,0)
            var finalArgs = args.concat(innerArgs)
            this.apply(obj,finalArgs)
        }
    }
}


複製程式碼

常用方法

  • 陣列去重
//es6 先轉化為Set資料結構再,通過擴充套件運算子(...),轉化為陣列
//擴充套件運算子(...)內部使用for...of迴圈
[...new Set(arr)]

複製程式碼
  • 類陣列轉化為陣列
//es6 通過擴充套件運算子(...)轉化
[...document.querySeletorAll('div')]

// es6  Array.from()
Array.from(new Set(document.querySeletorAll('div')))

//es5 借用陣列的slice方法 拷貝一份

// [].slice.call(likeArray)
Array.prototype.slice.call(document.querySeletorAll('div'),0)
Array.prototype.slice.call(arguments,0)
複製程式碼

正則提取url中的引數

  • 獲取指定URL引數
function getUrlParams(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); //定義正規表示式
    var r = window.location.search.substr(1).match(reg);  
    if (r != null) return unescape(r[2]);
  return null;
}

window.location = "http://www.baidu.com?name=elephant&age=25&sex=male";
var name = getUrlParams("name"); //elephant
var age = getUrlParams("age");   //25
var sex = getUrlParams("sex");&emsp;//male
複製程式碼

首先理解定義的正規表示式,(^|&)意思是從頭開始匹配字元&, =([^&]*)意思是匹配=後面零個或多個不是&的字元,直至碰到第一個&為止,(&|$)意思就是匹配最後一個&,在正規表示式中,增加一個()代表著匹配陣列中增加一個值, 因此程式碼中的正則匹配後陣列中應包含4個值, 在getUrlParams("name")函式中,此時 r 獲取到的陣列應該是 ["name=elephant&", "", "elephant", "&"]程式碼中 window.location.search 意思是取window.location中 '?'後面的值包括'?',因此所得到的值是"?name=elephant&age=25&sex=male" substr()這個函式的作用是擷取字串,在程式碼中window.location.search.surstr(1) 意思就是擷取第一個字元後面的字串,所得到的值即是"name=elephant&age=25&sex=male" unescape這個函式的作用是解碼escape編碼後的字串

  • 獲取所有的URL引數
function parse_url(_url){ //定義函式
&emsp;&emsp;var pattern = /(\w+)=(\w+)/ig;//定義正規表示式
&emsp;&emsp;var parames = {};//定義陣列
&emsp;&emsp;url.replace(pattern, function(a, b, c){
&emsp;&emsp;&emsp;&emsp;parames[b] = c;
&emsp;&emsp;});
&emsp;&emsp;return parames;//返回這個陣列.
}

var  url = "http://www.baidu.com?name=elephant&age=25&sex=male"
var params = parse_url(url);// ["name=elephant", "age=25", "sex=male"]
複製程式碼

當replace匹配到name=elephant時.那麼就用執行function(a,b,c);其中a的值為:name=elephant,b的值為name,c的值為elephant;(這是反向引用.因為在定義正規表示式的時候有兩個子匹配.),然後將陣列的key為name的值賦為elephant;然後完成. 再繼續匹配到age=25;此時執行function(a,b,c);其中a的值為:age=25,b的值為age,c的值為25;然後將陣列的key為id的值賦為25.

相關文章