基礎閉包

閉包

1、什么是閉包

fn套fn,內部fn可引用外部fn的參數和變量
內部被引用的參數和變量,不會被JS垃圾回收機制收回

2、閉包有什麼好處,哪方面應用

1).希望一個變量長期在內在中
2).避免全局變量污染
  a.模塊化代碼
  b.在循環中找到對應元素的索引
3).私有成員存在

3、閉包注意的地方

IE下可能引發內存洩漏

最簡單例子首先:

function aaa() {
  var a = 1;
}
aaa() //执行完后即会被垃圾回收机制收回*/

fn套fn,內部fn可引用外部fn的參數和變量

function aaa() {
  var a = 5;
  function bbb() {
    alert(a)
  }
  return bbb;
}
var c = aaa(); //这里aaa()已经执行完
c(); //c(),表示bbb函数*/

再一個:a能累加,但必須是全局變量

var a = 1;
function aaa() {
  a++;
  alert(a)
}
aaa(); //2
aaa(); //3
alert(a) //a是全局,所以能调用到,下面需要变成局布变量;

內部被引用的參數和變量,不會被JS垃圾回收機制收回

問題:如何使a在執行過程中有效,比如a++能累加,並且a又是一個局部變量?

//當a是局部變量時,不會累加了
function aaa() {
  var a = 1;
  a++;
  alert(a);
}
aaa(); //2
aaa(); //2 ,调用重新生成,不会累加,下面 既让a是局布变量,又可以累加*/
function aaa() {
  var a = 1; //相对于内部可被找到,又不受外部执行函数影响
  return function () { //函数嵌套函数
    a++;
    alert(a)
  }
}
var b = aaa()
b(); //2
b(); //3  即时局布变量又能累加
alert(a) //a is not defined,说明a是局部变量*/

問題:如何把以上函數聲明改寫為函數表達式?

//常識: 
function aaa() {
  alert(1)
}
aaa()
//該寫為函數表達式:
(function () { //可以把aaa去掉
  alert(1)
}) ();

所以問題的答案是:
a.模塊化代碼

var aaa = (function () { //aaa是函数执行完后的返回值
  var a = 1;
  return function () {
    a++
    alert(a)
  }
}) ()
aaa(); //2  aaa(),执行的即是return 后的函数
aaa(); //3  a在外面调用不到,又能累加,模块化代码;

問題:定義函數的私有方法?

var aaa = (function () {
  var a = 1; //a是局部变量,bbb,ccc是它的私有方法 在aaa函数外面调用不到
  function bbb() {
    a++;
    alert(a)
  }
  function ccc() {
    a++;
    alert(a)
  }
  return {   //特別留意:定義形式
    b: bbb,
    c: ccc
  }
}) ()
aaa.b() //2  調用
aaa.c() //3  調用
alert(a) //not defined
alert(bbb) //not defined
alert(ccc) //not defined

b.在循環中找到對應元素的索引

<ul>
    <li>第0個li</li>
    <li>第1個li</li>
    <li>第2個li</li>
</ul>
var li = document.getElementsByTagName('li')
for (var i = 0; i < li.length; i++) {
  li[i].onclick = function () {
    alert(i) //都是3 ,循环执行结束时i=3,alert还未执行,当去点击时才会执行
  }
}

解決一:循環中i當參數傳進來

for (var i = 0; i < li.length; i++) {
  (function (i) { //1、先写匿名函数,当去执行时把i传进来
    li[i].onclick = function () { //2、内部函数可以调用外部函数传进来的参数;
      alert(i)
    }
  }) (i)
}

解決二:寫return返回

for (var i = 0; i < li.length; i++) {
  li[i].onclick = (function (i) { //1、当点击时,3、执行完时 5、然后把i传进来
    return function () { //4、写return返回值
      alert(i)
    }
  }) (i) //2、先执行一次 5、把i传进去 
}      //7、因循环时,执行完毕后i已经存在内存中的i,调用时不是外面的i,所以能弹出0,1,2

iE下可能引发内存泄漏
問題描述:当一个变量box由dom获取或数组对象获取时,它的属性如onclick去引用一个内部fn,内部函数的对像box是去引用外面的,即会引发内部泄漏,IE下首尾互相引用时
解決:onunload後把對像變為null; 提前在外面引用,之後對象置null

var box = document.getElementById('box')
box.onclick = function () {
  alert(box.id)
}

解決一:

window.onunload = function () {
  box.onclick = null; //onunload后把box变为null即可
}

解决二:提前在外面引用,比如 var id = box.id,里面调用alert(id),之后對象置null;

var id = box.id
box.onclick = function () {
  alert(id)
}
box = null;

簡單枚舉 | iframe

枚舉:
1、用for從眾多可能出現的答案中找匹配;
2、即通過if找正確的答案。

<p>
    <span>A</span>
    <span>B</span>
    <span>C</span>
    <span>D</span>
    <span>E</span>
</p>
<p>
    <span>A</span>
</p>
<p>
    <span>E</span>
    <span>E</span>
    <span>E</span>
    <span>E</span>
    <span>E</span>
</p>
var _p = document.getElementsByTagName('p')
var _span0 = _p[0].getElementsByTagName('span')
var _span1 = _p[1].getElementsByTagName('span')
var _span2 = _p[2].getElementsByTagName('span')
//枚舉算法,用for從眾多可能出現答案的條件中找匹配,即通過if正確的答案
for (var i = 1; i <= 9; i++) { //A
  for (var j = 0; j <= 9; j++) { //B
    for (var k = 0; k <= 9; k++) { //C
      for (var m = 0; m <= 9; m++) { //D
        for (var n = 0; n <= 9; n++) { //E
          var a = 10000 * i + 1000 * j + 100 * k + 10 * m + n; //_p[0]
          var b = i; //_p[1]
          var c = n * 111111; //_p[2]
          if (a * b == c) {
            _span0[0].innerHTML = i;
            _span0[1].innerHTML = j;
            _span0[2].innerHTML = k;
            _span0[3].innerHTML = m;
            _span0[4].innerHTML = n;
            _span1[0].innerHTML = i;
            for (var z = 0; z < _span2.length; z++) {
              _span2[z].innerHTML = n
            }
          }
        }
      }
    }
  }
}

枚舉小例:
點擊任意a,當前innerHTMl加到ul,若已存在不加[方法返回false],若不存在添加[方法返回true]
要點,創建方法檢測當前點擊innerHTMl是否存在於頁面
拓展:如已存在,則把當前點擊項移到最前面

<a href="javascript:;">北京</a>
<a href="javascript:;">上海</a>
<a href="javascript:;">深圳</a>
<a href="javascript:;">廣州</a>
<a href="javascript:;">杭州</a>
<a href="javascript:;">天津</a>
<a href="javascript:;">成都</a>
<ul id="ul">
</ul>
var a = document.getElementsByTagName('a')
var ul = document.getElementById('ul')
var li = ul.getElementsByTagName('li')
for (var i = 0; i < a.length; i++) {
  a[i].onclick = function () {
    if (mj(this.innerHTML)) { //如果當前innerHTML 沒有相同返回 true
      var _li = document.createElement('li');
      _li.innerHTML = this.innerHTML;
      if (!li[0]) {
        ul.appendChild(_li)
      } 
      else {
        ul.insertBefore(_li, li[0])
      }
    } 
    else { //有相同返回false,無法添加,但可以把當前點擊移到最前面
      mj2(this.innerHTML)
    }
  }
}
//檢測方法
function mj(txt) {
  var result = true;
  for (var i = 0; i < li.length; i++) {
    if (li[i].innerHTML == txt) { //可能出現的找匹配,如果已存在
      result = false
    }
    //  else{result = true;}//切換即可添加 特別留意理解這句放與不放
  }
  return result;
}
function mj2(txt) { //當前新添加移到最上面
  for (var i = 0; i < li.length; i++) { //眾多可能出現的
    if (li[i].innerHTML == txt) { //創建條件
      ul.insertBefore(li[i], li[0])
    }
  }
}
}



操作iframe

1、_iframe.contentWindow.document.getElementById('box') 無兼容性

2、_iframe.contentDocument.getElementById('box') IE6/7不支持
主html

<input type="button" value="操作window"/>
<input type="button" value="操作document"/>
<input type="button" value="該變iframe大小一"/>
<input type="button" value="該變iframe大小二"/>
<iframe src="iframe-被嵌套1.html" frameborder="0" scrolling="no"></iframe>
<iframe src="iframe-反操作.html" frameborder="0"></iframe>
<div id="box">這是正常文檔的內容,被iframe反操作的box</div>
var _iframe = document.querySelectorAll('iframe') [0]
var _iframe2 = document.querySelectorAll('iframe') [1]
var inp = document.querySelectorAll('input') [0]
var inp2 = document.querySelectorAll('input') [1]
var inp3 = document.querySelectorAll('input') [2]
var inp4 = document.querySelectorAll('input') [3]
inp.onclick = function () {
  console.log(_iframe.contentWindow); //iframe的window對象,無兼容性
  _iframe.contentWindow.document.getElementById('box').style.background = 'red'
}
inp2.onclick = function () {
  _iframe.contentDocument.getElementById('box').style.color = '#fff'
  //IE6/IE7不支持
}

iframe-被嵌套1.html

<div id="box">這是iframe裏的內容,被所調用的操作</div>
<div style="width: 300px;height: 300px;background: #f90;"></div>

iframe反操作

iframe-反操作.html
1、window.parent 獲取父層頁面;
2、window.top 獲取最頂層頁面;
3、iframe防止被嵌套;if(window!=window.top){ window.top.location.href = window.location.href; }

<input type="button" value="iframe反操作" />
<div style="width: 200px;height: 200px;background: green;"></div>
var inp = document.querySelector('input')
//獲取父層的頁面 window.parent
inp.onclick = function () {
  window.parent.document.getElementById('box').style.background = 'peru' //無兼容性
}
//window.top最頂層
window.top.document.getElementById('box').style.color = '#fff'

//防止被嵌套
if (window != window.top) { //當前window !=最頂層window
  window.top.location.href = window.location.href; //跳轉至頁面
}

iframe.onload 事件

var _iframe = document.createElement('iframe')
_iframe.src = 'iframe-反操作.html'
document.body.appendChild(_iframe)
//        _iframe.onload = function () {
//            alert(123)
//        }
//ie: iframe.onload 事件 只能用綁定的形式;
_iframe.attachEvent('onload', function () {
  //alert(123)
})

iframe 設置寬高
如多頁面切換需設置定時器,否則會因執行太快而產生bug設置失效

function changeHeight() {
  setTimeout(function () { 
    _iframe.height = _iframe.contentWindow.document.body.offsetHeight //本頁面展示的高 = iframe頁面展示的高
  }, 100)
}

//使用
inp3.onclick = function () {
  _iframe.src = 'iframe-被嵌套1.html'
  changeHeight()
}
inp4.onclick = function () {
  _iframe.src = 'iframe-反操作.html'
  changeHeight()
}
//JQuery获得iframe的window对象
var win = $('#ifr')[0].contentWindow;  

//JS原生方法获得iframe的window对象
document.getElementById("ifr").contentWindow;  

$('#ifr')[0].contentWindow 和 document.getElementById("ifr") ;

var ifr1 = document.getElementById("ifr");  
var ifr2 = window.frames[0];  
ifr2.frameElement 是等价于 ifr1;