基礎事件委託 | 歷史管理 | firebug | 快速排序 |遞歸 筆記

事件委託:利用冒泡原理,把事件添加至父級上,觸發執行效果;
好處:1、提高性能;2、新添加元素還會有之前的事件,如新浪圍脖發布效果;
操作要點:1、添加事件到父級;2、找到當前的事件源,在事件源觸發;
兼容寫法: ie:window.event.srcElement 標準:window.event.target
之後使用nodeName判斷標籤源;

<input type="button" value="add" id="inp"/>
<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>
var ul = document.getElementById('ul1')
var li = ul.getElementsByTagName('li')
ul.onmouseover = function (ev) {
  var ev = ev || event;
  var target = ev.target || ev.srcElement
  if (target.nodeName.toLowerCase() == 'li') {
    target.style.background = 'red'
  }
}
ul.onmouseout = function (ev) {
  var ev = ev || event;
  var target = ev.target || ev.srcElement //當前操作事件源,比如移動到li即li,移動到ul即ul
  if (target.nodeName.toLowerCase() == 'li') { //只移動到li觸發
    target.style.background = ''
  }
}
//新添加元素還會有之前的事件,如使用for新加元素不會綁定事件
var inp = document.getElementById('inp')
var i = 0;
inp.onclick = function () {
  i++;
  var oli = document.createElement('li')
  oli.innerHTML = 555 * i;
  ul.appendChild(oli);
}



歷史管理

1、onhashchange:事件,當hash有變化時觸發;

2、histoty:事件
存:pushState(數據,標題[未實現],網址顯示)
讀:onpopState事件 event state;注意:網址顯示虛假,使用時須服務器指定

onhashchange簡陋例子

<input type="button" value="生成隨機數" id="inp"/>
<div id="box"></div>
var inp = document.getElementById('inp')
var box = document.getElementById('box')
inp.onclick = function () {
  var num = randomNum(49, 7); //49選7
  box.innerHTML = num;
  window.location.hash = num; //window.location.hash添加值
}
window.onhashchange = function () {
  var num = window.location.hash.substring(1) || '';
  box.innerHTML = num; //當改變時觸發;
}
//隨機數生產方法封裝
function randomNum(alls, now) {
  var arr = []
  var Newarr = []
  for (var i = 1; i <= alls; i++) {
    arr.push(i);
  }
  for (var i = 0; i < now; i++) {
    Newarr.push(arr.splice(Math.floor(Math.random() * arr.length), 1))
  }
  return Newarr;
}

網址變更

var inp = document.getElementById('inp')
var box = document.getElementById('box')
var obj = {} //利用對象
inp.onclick = function () {
  var num = randomNum(49, 7);
  box.innerHTML = num;
  var oRD = Math.random(); //生成隨機數 0.xxxxxxx
  obj[oRD] = num; //對像對應關係,每一個隨機數對應每一個num;
  window.location.hash = oRD; //實際上相當於處理下標元素
}
window.onhashchange = function () {
  var num = obj[window.location.hash.substring(1) || ''];
  box.innerHTML = num; //所以這裏需要套obj, '' 為防止undefined
}

histoty例子

var inp = document.getElementById('inp')
var box = document.getElementById('box')
var i = 1;
inp.onclick = function () {
  var num = randomNum(49, 7);
  box.innerHTML = num;
  history.pushState(num, '', i++); //存到history,這裏第三個參數為可選,可不填寫
}
window.onpopstate = function (e) { //當改變時執行讀取
  e = e || event
  var num = e.state || ''; 
  box.innerHTML = num;
}



跨域
ajax: XMLHttpRequest();不能跨域
jsonp:json + padding [把json放在盒子裏]<blockquote>
1、document.domain = 'xx.com'

2、服務器代理:XMLHttpRequest代理文件

3、script標籤:jsonp

4、location.hash

5、window.name

6、flash

7、html5 postMessage

</blockquote>

function createJS(sUrl){
    var _Script = document.createElement('script')
    _Script.src = sUrl;
    document.getElementsByTagName('head')[0].appendChild(_Script);
}
createJS('jsonp.js')
//createJS('jsonp.js?callback = box')

function box(){
    alert(json.name);
}
//box({name:elmok})  放到jsonp.js文件裏

hash值

<iframe src="xxx.php#key1=value1&key2=value2" frameborder="0"></iframe>
parent.location.hash = self.location.hash; //ie chrome不支持

firebug

console.group('')
console.log('abc')
console.groupEnd('')

console.dirxml(box) //顯示當前元素代碼結構

console.assert(20 == '20') //斷言假提示,成功不提示

function a(){return b()};
function b(){return c()};
function c(){console.trace();return 1}; //當前fn執行過程
a();

console.time('計時器')
    for(var i=0;i<10000;i++){
    }
console.timeEnd('計時器')  //計算fn執行時間

function a() {  //部分fbug無法顯示!
  for (var i = 0; i < 10; i++) {
    b(); //調用10次b
  }
  for (var i = 0; i < 5; i++) {
    c(); //調用5次c
  }
  function b() {
    var b = 10;
  }
  function c() {
    var c = 5;
  }
}
console.profile();
a();
console.profileEnd();

快速排序

30 12 5 6 9 18 57 2
取基准點9,9跟其他數比, [小於] 9 [大於]
5 6 2 9 30 12 18 57
取基准點 30 [小於] 30 [大於]
5 6 2 9 12 18 30 57
...以此類推
利用遞歸進行下次比較

//方法封裝

function quickSort(arr) {
  if (arr.length <= 1) { //有可能為0
    return arr;
  }
  var num = Math.floor(arr.length / 2) //向下取整,找到中間數
  var numV = arr.splice(num, 1); //找到基準點的數值
  var left = []; //存小於基准點的值
  var right = []; //存大於基準點的值
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < numV) {
      left.push(arr[i]);
    } 
    else {
      right.push(arr[i]);
    }
  }
  //以上一次操作,下面再利用遞歸原理
  return quickSort(left).concat([numV], quickSort(right));
  //左邊.concat(基准數,右邊)
}
alert( quickSort([30,12,5,6,9,18,57,2]) )



函数声明与函数表达式

函数声明:function 函数名(){}

函数表达式:function 函数名(){},命名与匿名表达式;

function aaa() {} //函数声明

var a = function aaa() {} //命名函数表达式
var b = function () {} //匿名函数表达式

(function aaa() {}) //函数表达式
~function aaa() {} //函数表达式
-function aaa() {} //函数表达式
+function aaa() {} //函数表达式
~function aaa() {} //函数表达式

区别:1、函数表达式可直接后面加括号执行,函数声明不行;

 2、函数声明可以被提前解析出来;<br />

在一些语句中若想执行不同函数时,不要用函数声明,用函数表达式;

if (true) {
  function bbb() {
    alert(1)
  }
} 
else {
  function bbb() {
    alert(2)
  }
}
a(); //ff、IE11正常弹1,其它弹2 [因为函数声明被预解析],

所以修改为:

if (true) {
  var a = function bbb() {
    alert(1)
    alert(typeof bbb)
  }
} 
else {
  var a = function bbb() {
    alert(2)
  }
}
a();//正常都弹1
bbb() //IE8下能弹出2,其它出错 [IE8下解析成两个函数 a(), bbb()]bbb()外面找不到,里面可找到,外面不要去调用函数表达式;



對象引用
遞歸算法:1、函數調用函數,永遠不會return,遞的過程

2、最後一次判斷一個終止條件,可以執行歸的動作。終止條件必須寫在最前面

典型例子:階乘

function factorial(n) {
  if (n == 1) { return 1 } //條件,最後一次為1 終止條件寫在最前面
  return n * factorial(n - 1);
}
console.log(factorial(5));
var a = 5;
var b = a;
b += 3;
alert(b) //b的改变不会影响到a,赋值类型
var arr = [1,2,3]
var arrN = arr //arrN與arr指向同一地址
arrN.push(4)
console.log(arrN); //[1,2,3,4]
console.log(arr); //[1,2,3,4] 影响到arr,对象和函数都是地址引用的关系
var arr = [1,2,3]
var arrN = arr
arrN = [1,2,3,4] //相当于赋另一块地址给arrN,arrN重新战胜一块地址,与arr分离
console.log(arrN); //[1,2,3,4]
console.log(arr); //[1,2,3]
var obj = {
  a: 10
}
var objN = obj;
objN.a = 20;
console.log(obj.a); //20,复制对象的问题,改变objN,同时影响到obj*/

第一種:淺拷貝

var obj = {
  a: 10
}
function copyO(obj) {
  var newO = {
  };
  for (var attr in obj) {
    newO[attr] = obj[attr]; //所有值都复制给新对象
  }
  return newO
}
var objN = copyO(obj);
objN.a = 20;
console.log(obj.a); //10  只有一層不會影響

第二種:深拷貝

var obj = {
  a: {b: 10} // 可能會有無數層
}
function deepcopyO(obj) { //深拷貝 遞歸
  if (typeof obj != 'object') { //什麼時候不是對象即能返回
    return obj;
  }
  var newO = {};
  for (var attr in obj) {
    newO[attr] = deepcopyO(obj[attr]); //進入下一層拷貝
  }
  return newO
}
var objN = deepcopyO(obj);
objN.a.b = 20;
console.log(obj.a.b); //10,再多層也不影響