美文网首页
JavaScript笔记2

JavaScript笔记2

作者: 王大吉Rock | 来源:发表于2018-12-12 23:24 被阅读15次

this、高阶函数、闭包、箭头函数、generator

1. this

函数this指向问题:
(1)this和它声明环境无关,而完全取决于他的执行环境,this指向函数调用时的对象。
(2)嵌套函数中的this不会继承上层函数的this,如果需要,可以用一个变量保存上层函数的this。

this的简单例子

function logthis() {
   return this;
}

var persion = {
   name :'wangdaji',
   logme: function() {}
};
persion.logme = logthis;

logthis();             // window
logthis.apply(persion);// persion
logthis.call(persion); // persion
persion.logme();       // person

this使用call()apply()来指定对象

// 全局变量
window.a = 1;
window.b = 2;

// oo对象
var oo = {
   a : 1,
   b : 2
};

function add(c, d) {
   return this.a + this.b + c + d;
}

add(3, 4);            // 10 , this is window
add.apply(oo, [3, 4]);// 10 , this is oo
add.call(oo, 3, 4);   // 10 , this is oo

this的进阶例子

// p1对象
var p1 = {
   name: 'wangdaji',
   eat: function() {
       console.log(this.name + ' eatting');
   }, 
   run: function() {
      var toRun = function() {
          console.log(this.name + ' running');
      }
      toRun();
   }
};

// p2对象
var p2 = {
   name: 'xiaoming',
   eat: function() {
       console.log(this.name + ' eatting');
   }, 
   run: function() {
      var that = this;
      var toRun = function() {
          console.log(that.name + ' running');
      }
      toRun();
   }
};

console.log(p1.eat()); // wangdaji eatting
console.log(p1.run()); // undefined running

console.log(p2.eat()); // xiaoming eatting
console.log(p2.run()); // xiaoming running

// ---注意点---
p1.eat = p2.eat;
p1.run = p2.run;

console.log(p1.eat()); // wangdaji eatting
console.log(p1.run()); // wangdaji running

// ---注意点---
var action = function () {};
action = p2.run;

console.log(action.apply(p1)); // wangdaji running

this本质
参考:http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

变量在内存中的数据结构:

var obj = { foo:  5 };

函数在内存中的数据结构:

var obj = { foo: function () {} };

this在内存数据结构中的理解:
由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

执行f():函数f在全局环境执行,this.x指向全局环境的x。

执行obj.f():在obj环境执行,this.x指向obj.x。


2. 高阶函数

JavaScript的函数其实都指向某个变量。变量可以指向函数,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

实现:[1, 2, 3, 4] ==> [1, 4, 9, 16]

var arr = [1, 2, 3, 4];

function square(x) {
   return x * x;
}

function mapp(f) {
   var arrr = new Array();
   this.forEach(function(e, i, arr) {
       arrr.push(f(e));
   });
   return arrr;
}

arr.mapp = mapp;

// 最终调用
var squareArr = arr.mapp(square);
console.log(squareArr);

数组的mapreducefiltersort方法:

map:传入一个函数,把传入的函数依次作用于每个元素,然后根据返回值组成的数组返回。

实现:[1, -2, 3, -4] ==> [1, 2, 3, 4]

var arr = [1, -2, 3, -4];

var results = arr.map(Math.abs);

console.log(results);

reduce:传进一个函数,此函数接受两个参数,把结果继续和序列的下一个元素做累积计算。
实现:[1, 2, 3, 4] ==> 1234

var arr = [1, 2, 3, 4];

var results = arr.reduce(function (x, y) {
    return x * 10 + y;
});

console.log(a);

filter:传入一个函数,把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。

// 将数组去重
var results, 
    arr = ['apple', 'strawberry', 'banana', 'pear', 'apple', 'orange', 'orange', 'strawberry'];

results = arr.filter(function (element, index, self) {
   return self.indexOf(element) === index;
})
console.log(results.toString());

sort():用于排序的,Array的sort()方法默认把所有元素先转换为String再排序。sort()是一个高阶函数,可以传入比较规则。

js中因为Array的sort()方法默认把所有元素先转换为String再排序,所以不能将数字直接进行排序。

3. 闭包

变量的作用域:父对象的的所有变量对子对象是可见的,反之不可以。

闭包是函数的指针,使用闭包可以访问函数内部的局部变量,而且局部变量的值可以一直保持在内存中。

acc和acc1就是闭包,但两者不相等,是不同的对象,并且对应函数内部的变量也是不同的。

// 初始值 + 数字数组每一元素 的和
function account(initial) {
   var sum = 0 + initial;
   return function (...rest) {
      rest.forEach(function(e, i, a) {
          sum += e;
      });
      return sum;
   }
}

// acc父函数,result子函数,不管result执行多少次,acc中的sum参数会一直存在
var acc = account(10);
var result = acc(1, 1, 1);
console.log(result);

var result = acc(2, 2, 2);
console.log(result);

闭包使用的注意点:
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大。(2)如果子函数是公用方法,直接使用子函数可能会修改到父函数中的私有变量,那么会导致数据的异常。

4. 箭头函数

练习:

// 一个参数
var pow2 = function (x) {
    return x * x;
}

console.log(pow2(11));

var fn = x => x * x;

console.log(fn(11));

// 没有参数
var pi = () => 3.14
console.log(pi());

// 多个参数 和 函数实现
var mylog = (x, y, ...rest) =>  {
   console.log(x);
   console.log(y);

   rest.forEach(function(e, i, a) {
     console.log(e);
   });
}
mylog(1, 10, 2, 30, 59);

箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj。


// 没有使用箭头函数
var p1 = {
   name: 'xiaoming',
   run: function () {
     that = this;
     var fn = function () {
        console.log(that.name + ' runing');
     }
     return  fn();
   }
};
p1.run();

// 使用箭头函数
var p = {
   name: 'wangfaji',
   run: function () {
     var fn = () =>  console.log(this.name + ' runing');
     return  fn();
   }
};
p.run();

此处的this指向的是p对象。

5. generator

generator(生成器)是ES6标准引入的新的数据类型。类似函数的定义方式,可以简单理解成可以返回多次的函数
generator定义:function*来定义。用yield返回多次。

一个id自增的generator。

function *nextid(a) {
  let x = 0;
  while(x < a) {
     yield ++x;
  }
  
  yield 12;

  yield 13;
}

// 只是一个generator对象,无法执行
var next = nextid(5);

console.log(next.next());// Object { value: 1, done: false }
console.log(next.next());// Object { value: 2, done: false }
console.log(next.next());// Object { value: 3, done: false }
console.log(next.next());// Object { value: 4, done: false }
console.log(next.next());// Object { value: 5, done: false }
console.log(next.next());// Object { value: 12, done: false }
console.log(next.next());// Object { value: 13, done: false }
console.log(next.next());// Object { value: undefined, done: true }

next()方法会返回generator的代码的下一个yield后面的值。

for of ,则不需要判断done的参数,并直接返回value值。

for (let value of nextid(5)) {
    console.log(value);
}

generator还有另一个巨大的好处,就是把异步回调代码变成“同步”代码。

相关文章

网友评论

      本文标题:JavaScript笔记2

      本文链接:https://www.haomeiwen.com/subject/kuumhqtx.html