1.箭头函数不适用的场合

由于箭头函数使得this从“动态”变成“静态”,下面两个场合不应该使用箭头函数。

  • 第一个场合是定义对象的方法,且该方法内部包括this。

    1. const cat = {
    2. lives: 9,
    3. jumps: () => {
    4. this.lives--;
    5. }}

    上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
    **

  • 第二个场合是需要动态this的时候,也不应使用箭头函数。

    1. var button = document.getElementById('press');
    2. button.addEventListener('click', () => {
    3. this.classList.toggle('on');});

    上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
    另外,如果函数体很复杂,有许多行,或者函数内部有大量的读写操作,不单纯是为了计算值,这时也不应该使用箭头函数,而是要使用普通函数,这样可以提高代码可读性。

2.注意点

  • 当 var s = function g(){}时,这是一个函数表达式,不是函数声明,g只能在函数内部访问,g是只读的。
  • es6对象中简写的函数体不能被new,es6中的箭头函数也不能被new。
  • 使用箭头函数返回对象时必须加一对括号,如:()=> ({a:1,b:2})。
  • es6中函数参数可以赋值默认值,如: ```javascript 1.function fn (x=1,y){ console.log(x,y) } fn() // 1,undefind 2.function fn1(a,b=1,c){ console.log(a,b,c); } fn1(2,,3) // 报错,不可以省略参数跳到后面的参数 fn1(2,undefind,3)// 2,1,3 如果要省略参数,只能写undefined来省略

参数变量是默认声明的,所以不能用let或const再次声明。

let x = 99; function foo(p = x + 1) { console.log(p); }

foo() // 100 x = 100; foo() // 101 默认值可以从外界拿取

  1. - 对象和立即执行函数不能挨着写,如果对象后面写立即执行函数,对象末尾必须带“;”,否则会报错。
  2. <a name="3HWaY"></a>
  3. ## 3.训练题
  4. <a name="bhwC2"></a>
  5. ### 1.if代码块问题
  6. ```javascript
  7. function a(){
  8. console.log(1);
  9. }
  10. (function(){
  11. if(false){
  12. function a(){
  13. console.log(2);
  14. }
  15. }
  16. a();
  17. })()
  18. 答案:
  19. 1.在ie10及ie10以下 输出2 因为在较老版本的浏览器中,无论条件是否为真,if(false)代码块中的函数声明整体提升,所以a函数执行后输出 2.
  20. 2.在现在的浏览器中会报错 Error:a is not a function,同样,无论条件是否为真,函数声明还是被提升了,但是浏览器更新后,在不符合条件的判断语句中,函数并不是整体进行提升,而只是被声明成了一个变量 即 var a;

2.手写深拷贝

function deepClone(target,origin){
        var target = target || {};
        var arr = '[object Array]';
        for(var prop in origin){
            var key = origin[prop];
            if(typeof key !== "object" && typeof key !== null){
                target[prop] = key;
            }else{
                if(Object.prototype.toString.call(key) == arr){
                    target[prop] = [];
                }
                deepClone(target[prop],key);
            }
        }
        return target;
    }

3.写出程序输出的值

this.a = 20;
    var test = {
        a:40,
        init:() => {
            console.log(this.a);
            function go() {
                this.a = 60;
                console.log(this.a);
            }
            go.prototype.a = 50;
            return go;
        }
    };
    var p = test.init();
    p();
    new(test.init())();
 答案:
    20 60 60 60,在p被执行时,go函数中的this指向window,把原本的window.a的值修改成了60,所以第三次输出60.

4.手写bind方法

Function.prototype.mybind = function(other){
        var self = this;
        // 判断调用bind方法的是否是一个函数
        if(typeof self !== "function"){
            throw new Error("这不是一个函数,不能调用bind方法");
        }
        var slice = Array.prototype.slice,
            ProFn = function() {},
            thisArg = slice.call(arguments,1),
            bound = function(){
                var thatArg = slice.call(arguments);
                return self.apply(this instanceof bound ? this : other,thisArg.concat(thatArg));
            };
            if(self.prototype){
                ProFn.prototype = self.prototype;
            }
            bound.prototype = new ProFn(); //防止篡改父级的原型
            return bound;
    }

5.手写call

Function.prototype.myCall = function(thisArg, ...args) {
    if(typeof this !== 'function') {
        throw new TypeError('error')
    }
    const fn = Symbol('fn')        // 声明一个独有的Symbol属性, 防止fn覆盖已有属性
    thisArg = thisArg || window    // 若没有传入this, 默认绑定window对象
    thisArg[fn] = this              // this指向调用call的对象,即我们要改变this指向的函数
    const result = thisArg[fn](...args)  // 执行当前函数
    delete thisArg[fn]              // 删除我们声明的fn属性
    return result                  // 返回函数执行结果
}