2017.08.25

new

闭包

  1. 使用场景:模拟面向对象中的类、立即执行函数、模拟方法工厂、模拟块级作用域、模拟私有变量

  2. 闭包的内存回收

影响闭包被回收的因素:内部函数是否使用了外部函数的变量

<button id="btnGetInner">getInner</button>
<button id="btnRunInner">runInner</button>
var getLargeObj = function (size) {
  var arr = [];
  var intSize = parseInt(size);
  for (var i = intSize.length - 1; i >= 0; i--) {
    for (var j = 199999; j >= 0; j--) {
      arr.push('abcdefghijklmnopqrstuvwxyz');
    }
  }
  return intSize;
}
function outer() {
  console.log('outer');
  var largeObject;
  if (!!window.ActiveXobject || "ActiveXobject" in window) {
    // ie 监控内存变化很方便,所以直接使用较大内存,了解内存的变化曲线
    largeObject = getLargeObj('100MB');
  } else {
    // 在 chrome 等浏览器下,监控内存不方便,所以保存1m的内存快照,来对比内存的变化
    largeObject = getLargeObj('1MB');
  }
  function help() {
    return largeObject;
    // eval('')
  }
  // inner 函数
  return function () {
    console.log('inner');
    return largeObject;
  }
}

document.getElementById('btnGetInner').onclick = function () {
  inner = outer();
  // 仅使用于 IE 浏览器,其他浏览器使用调试工具手动回收
  if (window.CollectGarbage) {
    CollectGarbage();
  }
}
document.getElementById('btnRunInner').onclick = function () {
  if (inner) {
    inner();
  }
}
  • 闭包中的没有被引用的变量会被垃圾回收,被引用的变量不会被回收。
  • 即使闭包中没有变量被引用,但是使用了 eval() 函数,会保留闭包中所有的局部变量以避免产生不可预期的结果,所以不回收闭包变量
  • 内部函数中使用 window.eval() ,只能访问到全局变量,所以闭包中的变量会被回收
  • 不仅返回的内部函数,其他被定义的内部 函数中使用了外部函数中的变量或 eval() 函数,也不能回收闭包中的内存

是否应该使用闭包? 在最新版的浏览器下,是可以使用闭包的。而在旧版中,特别是旧版IE中,不建议使用闭包。

如何高效地使用闭包?

  • 内部函数尽量少使用外部函数的局部变量
  • 内部函数尽量不要直接调用 eval 函数
  • 在退出函数之前,将不使用的局部变量全部删除或设置为 null ,断开变量和内存之间的联系

关卡挑战:

仔细想想,前3题会输出什么结果,并完成后面两道编码题。(建议完成时间:60分钟)

解题提示:深挖闭包的特性。


// 挑战一

var checkClosure = function() {

  var arr = [];

  for (var i = 0; i < 5; i++) {

    arr[i] = function() {

      return i;

    }

  }

  return arr;

};

var arr = checkClosure();

console.log(arr[0]()); // ???

console.log(arr[1]()); // ???

console.log(arr[2]()); // ???

console.log(arr[3]()); // ???

console.log(arr[4]()); // ???

// 挑战二

var add = function(x) {

  var sum = 0;

  var fn = function(x) {

    if (x) {

      sum = sum + x;

      return fn;

    } else {

      return sum;

    }

  }

  return fn;

}

console.log(add(1)(2)(3)(4)(5)());  // ???

// 挑战三

function checkClosure(n, o) {

  console.log(o);

  return {

    checkClosure: function(m) {

      return checkClosure(m, n);

    }

  };

}

var a = checkClosure(0);a.checkClosure(1);a.checkClosure(2);a.checkClosure(3); // ???,???,???,???

var b = checkClosure(0).checkClosure(1);b.checkClosure(2);b.checkClosure(3); // ???,???,???,???

var c = checkClosure(0).checkClosure(1).checkClosure(2);c.checkClosure(3);  // ???,???,???,???

var d = checkClosure(0).checkClosure(1).checkClosure(2).checkClosure(3); // ???,???,???,???

// 挑战四

// 定义一个函数 repeat,这个函数能返回一个新函数,调用 repeatedFun ("hello world"),会 alert 十次 hello world, 每次间隔5秒。

function repeat (func, times, wait) {}

var repeatedFun = repeat(alert, 10, 5000);

repeatedFun ("hello world");

// 挑战五

// 定义一个函数 stringconcat, 要求能实现以下功能。

var result1 = stringconcat("a", "b"); // result1 = "a+b"

var stringconcatWithPrefix = stringconcat.prefix("helloworld");

var result2 = stringconcatWithPrefix("a", "b"); // result2 = "helloworld+a+b"
  • this

this 在 javascript 中指的是函数执行时的上下文,跟函数定义时的上下文无关。随着函数使用场合的不同,this 的值会发生变化。但是有一个总的原则,那就是 this 指代的是调用函数的那个对象

  • 全局作用域中的this 恒等于 window
  • 函数作用域中的 this:外部函数作用域中的 this指代window(严格模式下,禁止使用全局对象,会报 undefined
  • 对象方法中的 this:动态绑定,运行时绑定,并不是定义时绑定
var o = {
  name: 'carlsiry',
  f: function() {
    console.log(this.name);
  }
}
o.f(); // carlsiry
function f3() {
  console.log(this.name); // 定义时的 this 指代 window
}
var o2 = {
  name = 'carlsiry'
};
o2.f = f3;
o2.f(); // carlsiry ,运行时绑定到了 o2 对象,指代 o2
  • 闭包中的 this:指代内部函数被调用时的执行环境
  • eval() 函数中的this:相当于对象方法
  • call() 和 apply() 方法中的this:指代传入的第一个参数对象,如果参数为空则默认指代 window对象
var x = 0;
var a = {x: 2};
var o = {
  x: 1,
  f: function() {
    console.log(x);
  }
};
o.f(); // 1
o.f.call(a); // 2
o.f.call(); // 1
  • bind() 方法中的 this:永久绑定到bind 的第一个参数
function test() {
  console.log(this.name);
}
var foo = test.bind({name: 'carl'});
foo(); // carl
var bar = {
  name: 'bar',
  test: test,
  foo: foo
};
bar.test(); // bar
bar.foo(); // carl
  • DOM事件处理函数中的this:当函数使用 addEventListener 作为事件处理函数时,它的this指向触发事件的元素(非IE);当函数使用 attachEvent 作为事件处理函数时,它的 this 指向 window 对象(IE浏览器)
  • 内联内联事件处理函数中的this:<a onclick="alert(this.tagName)">clickMe</a> 指代绑定的DOM的元素(注意如果是匿名函数,那么this 指代 window对象)

关卡挑战:

仔细想想,以下代码会输出什么结果?(建议完成时间:30分钟)

解题提示:

1.深挖 this 的 9 个使用场景。

2.部分挑战第一次执行的结果,会影响到第二次的执行结果。


// 挑战一

(function() {

  this.scope = "local";

})();

console.log(window.scope); // ???

// 挑战二

var scope = "global";  

var obj = {    

  scope: "local",

  getScope: function() {      

    return function() {        

      return this.scope;      

    };    

  }  

};  

console.log(obj.getScope()()); // ???

// 挑战三

var scope = "global";  

var obj = {    

  scope: "local",

  getScope: function() {  

    var that = this;     

    return function() {        

      return that.scope;      

    };    

  }  

};  

console.log(obj.getScope()()); // ???

// 挑战四

function a(x) {

  debugger;

  this.x = x;

  return this;

};

var x = a(5);

var y = a(6);

console.log(x.x); // ???

console.log(y.x); // ???

// 挑战5五

function obj() {

  this.scope = "local";

  return "global";

}

var obj = new obj();

console.log(obj);  // ???

// 挑战六

scope = "global";

var obj1 = {

  scope: "local1",

  getScope: function() {

    console.log(this.scope)

  }

};

var obj2 = {

  scope: "local2"

};

(obj2.getScope = obj1.getScope)();   // ???
  • 切图技巧

理解设计稿的“一页多状态”和交互方式

  1. 最小原则:背景平铺、合成雪碧图
  2. 最适原则:图片格式(jpg最小,png最真,gif最活,ico最细)

  3. 美化表单以及扒站技巧

    input {
    width: 200px;
    height: 30px;
    padding: 0 4px;
    border: 1px #ccc solid;
    border-radius: 2px;
    }
    /* focus */
    input {
    outline: none;
    }
    input::-webkit-input-placeholder {
    color: #ccc;
    }
    
  4. 扒站技巧:Webzip, HTTrack Website Copier, teleport pro, scrapbook(火狐附加组件)

  5. 网页分析技巧:转化路径分析、营销效果分析、来源分析

  6. 视屏缩略图布局与样式

<style type="text/css">
  .box{
    width: 170px;
    font-size: 12px;
    color: #3a3a3a;
  }
  .box .cut-img{
    height: 110px;
    position: relative;
    margin-bottom: 10px;
  }
  .box .cut-img p{
    color: #fff;
    margin: 0;
    position: absolute;
    left: 0;
    bottom: 0;
    width: 90%;
    padding:5px 5%;
  }
  .box .cut-img p i{
    display: inline-block;
    width: 0;
    height: 0;
    font-size: 0;
    line-height: 0;
    border:5px transparent solid;
    border-left: 8px #fff solid;
    vertical-align: middle;
  }
  .box .cut-img p span{
    display: inline-block;
    vertical-align: middle;
  }
  .box h3{
    margin:0 0 8px;
  }
  .box h3 a{
    color: #3a3a3a;
    text-decoration: none;
  }
  .box h3 a:hover{
    color: #e73c31;
  }
  .box p.muted{
    color: #909090;
    margin:0;
  }
</style>

<div class="box">
  <div class="cut-img">
    <img src="cut_pic.jpg" />
    <p><i></i><span>1,042万</span></p>
  </div>
  <h3><a href="#">评价女王</a></h3>
  <p class="muted">看“女王”怎么撩五男!</p>
</div>
  • SEO 优化:
  • 关键词分析
  • 网站目录、页面优化
  • 内容发布和链接布置
  • 建立网站地图(SiteMap)

results matching ""

    No results matching ""