空陣列與布林值的比較
// 先執行[].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
}
複製程式碼
常用的繼承方式
- 僅從原型繼承 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()
複製程式碼
- 原型鏈繼承(仿傳統)
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()
複製程式碼
- 借用建構函式法
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)
複製程式碼
- 臨時構造器法
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;
}
複製程式碼
- 使用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(){
    n=999;
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  
複製程式碼
各種專業文獻上的“閉包”(closure)定義非常抽象,很難看懂。我的理解是,閉包就是能夠讀取其他函式內部變數的函式。 由於在Javascript語言中,只有函式內部的子函式才能讀取區域性變數,因此可以把閉包簡單理解成“定義在一個函式內部的函式”。 所以,在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑。
- 它的最大用處有兩個,一個是前面提到的可以讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中。
- 由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。
- 閉包會在父函式外部,改變父函式內部變數的值。所以,如果你把父函式當作物件(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"); //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){ //定義函式
  var pattern = /(\w+)=(\w+)/ig;//定義正規表示式
  var parames = {};//定義陣列
  url.replace(pattern, function(a, b, c){
    parames[b] = c;
  });
  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.