ECMA基础(四)

this

thisJavaScript的关键字,是当前环境执行期上下文的一个属性,在不同的环境中node/window下表现是不同的

全局对象

  • 全局作用域下的this是全局对象this === window
  • web的全局对象有:window,self,frames
  • node的全局对象有:global
  • worker的全局对象有:self
  • globalThis可以拿到不同环境下的全局对象

严格模式

函数内部的this指向undefined

指向

  • 函数内部还没实例化的this指向window
  • 全局范围的this指向window
  • 预编译函数this指向window
  • apply/call改变this指向
  • 构造函数的this指向实例化对象

普通函数内部的this

  1. //this
  2. //函数内部的this
  3. //函数内部还没实例化的this指向window
  4. function test(b) {
  5. this.d = 3; //window.d = 3
  6. var a = 1;
  7. function c() {}
  8. }
  9. test(123);
  10. console.log(d); //3
  11. console.log(this.d); //3
  12. console.log(window.d); //3
  13. /**
  14. * A0 = {
  15. * arguments: [123],
  16. * this: window,
  17. * b: undefined -> 123,
  18. * a: undefined,
  19. * c: function c(){}
  20. * }
  21. */

构造函数的this

  1. //this指向实例化对象
  2. function Test() {
  3. //var this = {
  4. // __proto__: Test.prototype
  5. //}
  6. this.name = '123';
  7. }
  8. var test = new Test();
  9. //关于构造函数的AO/GO
  10. /**
  11. * new之前:
  12. * AO = {
  13. * this: window
  14. * }
  15. *
  16. * GO = {
  17. * Test: function Test(){...}
  18. * }
  19. /
  20. /**
  21. * new之后:
  22. * AO = {
  23. * this: {
  24. * name: '123',
  25. * __proto__: Test.prototype
  26. * }
  27. *
  28. * }
  29. *
  30. * GO = {
  31. * Test: function Test(){...},
  32. * test: {
  33. * name: '123',
  34. * __proto__: Test.prototype
  35. * }
  36. * }
  37. */

call()/apply()this

  1. //call / apply
  2. function Person() {
  3. this.name = 'zhangsan';
  4. this.age = 18;
  5. }
  6. function Programmer() {
  7. //this -> Person
  8. Person.apply(this);
  9. //引申: 如果Person函数有形参,需要传参数
  10. // Person.apply(this, [name, age]);
  11. this.work = 'Programming';
  12. }
  13. var p = new Programmer();
  14. console.log(p);

this进阶

预编译:

函数执行 -> AO-> 产生this-> this的指向与执行方式有关

  1. 默认绑定规则
  2. 隐式绑定规则: 对象调用(谁调用指向谁)

    1. 隐式丢失
    2. 参数赋值
  3. 显示绑定: call/apply/bind
  4. new绑定

优先级问题:

new显示 > 隐式 > 默认

  1. //1.默认绑定规则
  2. //全局this指向window
  3. console.log(this === window); //true
  4. //函数的独立调用: 函数内部this指向window
  5. function test() {
  6. console.log(this === window); //true
  7. }
  8. test();
  1. //2.隐式绑定规则: 对象调用(谁调用指向谁)
  2. //隐式丢失,参数赋值的情况,导致隐式绑定失败
  3. var a = 0;
  4. var obj = {
  5. a: 2,
  6. foo: function () {
  7. console.log(this); //{a: 2, foo: ƒ} //被抛出闭包后,这里this改变为window
  8. function test1() {
  9. console.log(this); //window
  10. }
  11. //函数独立调用指向window
  12. test1();
  13. //函数立即执行也算是函数独立调用
  14. (function () {
  15. console.log(this); //window
  16. })();
  17. //闭包: 当函数执行时导致函数被定义并抛出
  18. function test2() {
  19. console.log(this); //window
  20. }
  21. return test2;
  22. }
  23. }
  24. obj.foo();
  25. //调用闭包函数
  26. obj.foo()();
  1. //对象调用(谁调用指向谁)的例外
  2. //隐式丢失
  3. var a = 0;
  4. function foo1() {
  5. console.log(this);
  6. }
  7. var obj1 = {
  8. a: 2,
  9. foo1: foo1
  10. }
  11. obj1.foo1(); //this -> obj1
  12. //当前全局变量bar持有foo1的引用
  13. var bar = obj1.foo1;
  14. bar(); //this -> window
  15. //解读:
  16. //观察this在哪里执行
  17. //obj里执行指向obj
  18. //bar()独立调用执行window
  19. //当方法被重写/函数赋值时会存在隐式丢失 -> 函数独立调用
  20. //var bar = obj1.foo1; -> var bar = foo1; -> 函数独立调用foo1();
  1. //关于调用方式
  2. //独立调用的方式
  3. obj.foo();
  4. //以下三个不同的调用方式
  5. bar.call();
  6. bar.apply();
  7. bar.bind();
  1. //函数的参数赋值的情况
  2. //参数赋值也会存在丢失使内部调用函数变为独立调用执行
  3. var a = 0;
  4. function foo() {
  5. console.log(this); //只要独立调用 this -> window
  6. }
  7. //父函数是有能力决定子函数的this指向的
  8. function bar(fn) {
  9. //1.bar()执行内部产生this指向
  10. //2.fn形参在预编译时有赋值的过程 fn: obj.foo
  11. console.log(this);
  12. //3.foo() -> fn()独立调用执行
  13. // fn();
  14. //4.强行改变this指向
  15. // fn.call(obj); //this -> obj
  16. //5.还可以new 来改变this指向
  17. // new fn(); //this -> foo
  18. //6.还可以这样强行改变this指向
  19. // fn.bind(obj)(); //this -> obj
  20. }
  21. var obj = {
  22. a: 2,
  23. foo: foo
  24. }
  25. //obj.foo理解为持有foo引用地址的变量
  26. bar(obj.foo);
  1. //高阶函数里面参数的this
  2. //api接口中指明的
  3. var arr = [1, 2, 3];
  4. arr.forEach(function (item, idx, arr) {
  5. //这里的this由谁来决定?
  6. console.log(this); //window
  7. });
  8. arr.sort(function (a, b) {
  9. console.log(this);
  10. return a - b;
  11. });
  12. var t = setInterval(function () {
  13. console.log(this);
  14. })
  15. clearInterval(t);
  1. //3.显示绑定: call/apply/bind
  2. var obj = {};
  3. //call/apply/bind使用和传参
  4. //关于call/apply第一个参数默认绑定为window对象
  5. //如果绑定原始值会返回包装类
  6. obj.foo(1, 2, 3);
  7. bar.call(obj, 1, 2, 3);
  8. bar.apply(obj, [1, 2, 3]);
  9. bar.bind(obj)(1, 2, 3);
  1. //4.new绑定
  2. function Person() {
  3. // var this = {};
  4. // this.a = 1;
  5. // //这里的this实际上是函数实例化之后返回的结果
  6. // return this;
  7. return 1;
  8. }
  9. //this -> person
  10. var person = new Person();

练习题:

  1. var name = '222';
  2. var a = {
  3. name: '111',
  4. say: function () {
  5. console.log(this.name);
  6. }
  7. }
  8. var fun = a.say;
  9. fun(); //222
  10. a.say(); //111

关于优先级:

  1. //显示绑定vs隐式绑定,谁优先级更高?
  2. function foo() {
  3. console.log(this.a);
  4. }
  5. var obj1 = {
  6. a: 2,
  7. foo: foo
  8. }
  9. var obj2 = {
  10. a: 3,
  11. foo: foo
  12. }
  13. obj1.foo(); //2
  14. obj2.foo(); //3
  15. //call能更改this的指向,说明显示比隐式绑定优先级更高
  16. obj1.foo.call(obj2); //3
  17. obj2.foo.call(obj1); //2
  1. //new绑定vs显示绑定,谁优先级更高?
  2. //new更高
  3. function foo(b) {
  4. this.a = b;
  5. }
  6. var obj1 = {};
  7. var bar = foo.bind(obj1);
  8. bar(2);
  9. console.log(obj1.a); //2
  10. var baz = new bar(3);
  11. console.log(obj1.a); //2
  12. console.log(baz.a); //3
  1. //关于箭头函数
  2. function foo() {
  3. console.log(this); //obj -> obj.foo()
  4. //子函数默认独立调用指向window
  5. function test() {
  6. console.log(this); //this
  7. }
  8. test();
  9. //此时可以利用箭头函数让this指向obj
  10. var test2 = () => {
  11. //箭头函数内部默认没有this,而是直接拿父函数的this(外层函数的作用域的this)
  12. console.log(this); //obj
  13. }
  14. test2();
  15. }
  16. var obj = {
  17. a: 1,
  18. foo: foo
  19. }
  20. obj.foo();

全部绑定规则对箭头函数更改this的方法不适用,箭头函数中的this取决于父函数中this的指向

  1. //尝试更改箭头函数的this指向
  2. function foo() {
  3. console.log(this);
  4. var test = () => {
  5. console.log(this);
  6. }
  7. return test;
  8. }
  9. var obj1 = {
  10. a: 1,
  11. foo: foo
  12. }
  13. var obj2 = {
  14. a: 2,
  15. foo: foo
  16. }
  17. var obj3 = {
  18. a: 2,
  19. foo: () => {
  20. console.log(this);
  21. }
  22. }
  23. //默认绑定规则(独立调用 对箭头函数无效)
  24. obj1.foo()(); //this -> obj
  25. //隐式绑定规则(对象调用 对箭头函数无效)
  26. obj3.foo(); //this -> window
  27. //显示绑定规则(对箭头函数无效)
  28. //foo()执行完返回test, test.call(obj2)
  29. //如果call生效指向obj2
  30. var bar = foo().call(obj2); //this -> window
  31. //new绑定规则(对箭头函数无效) 不能实例箭头函数
  32. var foo = () => {
  33. console.log(this);
  34. }
  35. new foo(); //报错 没有constructor

应用场景:

例子1

  1. var name = 'window';
  2. var obj1 = {
  3. name: '1',
  4. fn1: function () {
  5. console.log(this.name);
  6. },
  7. fn2: () => console.log(this.name),
  8. fn3: function () {
  9. return function () {
  10. console.log(this.name);
  11. }
  12. },
  13. fn4: function () {
  14. return () => console.log(this.name);
  15. }
  16. }
  17. var obj2 = {
  18. name: '2'
  19. };
  20. //对象调用 谁调用指向谁
  21. obj1.fn1(); //this -> obj1
  22. //改变调用对象
  23. obj1.fn1.call(obj2); //this -> obj2
  24. //对象的箭头函数内部不存在this找父作用域的this
  25. obj1.fn2(); //this -> window
  26. //箭头函数不适用显示调用规则 无效 this原本是什么就是什么
  27. obj1.fn2.call(obj2); //this -> window
  28. //独立调用 指向window
  29. obj1.fn3()(); //this -> window
  30. //显形规则生效 改变指向
  31. obj1.fn3().call(obj2); //this -> obj2
  32. //外层改变指向,但是内层自己独立调用 所以指向window
  33. obj1.fn3.call(obj2)(); //this -> window
  34. //箭头函数内部不存在this找父作用域fn4,而fn4是通过对象obj1调用
  35. obj1.fn4()(); //this -> obj1
  36. //箭头函数内部不存在this找父作用域fn4,而fn4是通过对象obj1调用
  37. //这里call改变的是箭头函数指向但不生效
  38. obj1.fn4().call(obj2); //this -> obj1
  39. //箭头函数内部不存在this找父作用域fn4,而fn4是通过对象obj1调用但fn4被改变指向为obj2
  40. //这里call改变的是fn4指向生效
  41. obj1.fn4.call(obj2)(); //this -> obj2

构造函数

自定义构造函数

作用:

  • 模块化
  • 插件化
  • 组件化

写法:

  • 大驼峰(区分普通函数)
  1. //没执行之前,this不存在
  2. function Teacher() {
  3. this.name = 'zhangsan';
  4. this.sex = 'male';
  5. this.smoke = function () {
  6. console.log('I am smoking');
  7. }
  8. }
  9. //实例化之后,this执行指向实例对象
  10. var teacher1 = new Teacher();
  11. var teacher2 = new Teacher();
  12. teacher1.name = 'lisi';
  13. console.log(teacher1, teacher2);
  1. function Teacher() {
  2. this.name = 'zhangsan';
  3. this.sex = 'male';
  4. this.weight = 130;
  5. this.smoke = function () {
  6. this.weight--;
  7. console.log(this.weight);
  8. }
  9. this.eat = function () {
  10. this.weight++;
  11. console.log(this.weight);
  12. }
  13. }
  14. var t1 = new Teacher();
  15. var t2 = new Teacher();
  16. t1.smoke(); //130
  17. t1.smoke(); //129
  18. console.log(t2.weight); //130

传参:

  1. function Teacher(name, sex, weight, course) {
  2. this.name = name;
  3. this.sex = sex;
  4. this.weight = weight;
  5. this.course = course;
  6. this.smoke = function () {
  7. this.weight--;
  8. console.log(this.weight);
  9. }
  10. this.eat = function () {
  11. this.weight++;
  12. console.log(this.weight);
  13. }
  14. }
  15. var t1 = new Teacher('zhangsan', 'female', 145, 'JavaScript');
  16. var t2 = new Teacher('lisi', 'male', 98, 'HTML');
  17. console.log(t1);
  18. //Teacher {name: "zhangsan", sex: "female", weight: 145, course: "JavaScript", smoke: ƒ, …}
  19. console.log(t2);
  20. //Teacher {name: "lisi", sex: "male", weight: 98, course: "HTML", smoke: ƒ, …}

配置选项化:

  1. function Teacher(opt) {
  2. this.name = opt.name;
  3. this.sex = opt.sex;
  4. this.weight = opt.weight;
  5. this.course = opt.course;
  6. this.smoke = function () {
  7. this.weight--;
  8. console.log(this.weight);
  9. }
  10. this.eat = function () {
  11. this.weight++;
  12. console.log(this.weight);
  13. }
  14. }
  15. var t1 = new Teacher({
  16. name: 'zhangsan',
  17. sex: 'female',
  18. weight: 145,
  19. course: 'JavaScript'
  20. });
  21. var t2 = new Teacher({
  22. name: 'lisi',
  23. sex: 'male',
  24. weight: 98,
  25. course: 'HTML'
  26. });
  27. console.log(t1);
  28. //Teacher {name: "zhangsan", sex: "female", weight: 145, course: "JavaScript", smoke: ƒ, …}
  29. console.log(t2);
  30. //Teacher {name: "lisi", sex: "male", weight: 98, course: "HTML", smoke: ƒ, …}

实例化原理

一旦执行构造函数,this就会存在,并指向window

  1. function Car() {
  2. this.color = 'red';//=> window.color = 'red';
  3. }
  4. Car();

一旦实例化构造函数this指向实例对象

  1. function Car(color, brand) {
  2. this.color = color;
  3. this.brand = brand;
  4. }
  5. var car1 = new Car('red', 'Benz');
  6. var car2 = new Car('black', 'Mazda');
  7. console.log(car1.color); //red
  8. console.log(car2.color); //black

构造函数的this

构造实例化对象相当于普通函数执行:

  • 页面加载生成GO
  • 函数执行生成AO, 默认存了this对象
  • 当new的时候,走完构造函数内部的代码
  • 隐式的在构造函数内部底下加入return this;
  • this指向被赋值的变量并存入GO
  1. /**
  2. * 页面加载:
  3. * GO = {
  4. * Car: function
  5. * }
  6. * 函数Car执行:
  7. * AO = {
  8. * this: {}
  9. * }
  10. * 跑代码:
  11. * AO = {
  12. * this: {
  13. * color: color,
  14. * brand: brand
  15. * }
  16. * }
  17. * 将new出来的对象赋值给car1变量
  18. * 构造函数Car内部底下加入return this
  19. * this指向变量car1并存入GO
  20. * GO ={
  21. * Car: function,
  22. * car1: {
  23. * color: 'red',
  24. * brand: 'Benz'
  25. * }
  26. * }
  27. */
  28. function Car(color, brand) {
  29. this.color = color;
  30. this.brand = brand;
  31. //return this;
  32. //this => car1
  33. }
  34. var car1 = new Car('red', 'Benz');
  35. console.log(car1.color);

自己写一个new过程:

  1. function Car(color, brand) {
  2. var me = {};
  3. me.color = color;
  4. me.brand = brand;
  5. return me;
  6. }
  7. var car = Car('red', 'Mazda');
  8. console.log(car.color);
  9. console.log(car.brand);

试图强行修改return返回的this(默认return this)

  1. function Car() {
  2. this.color = 'red';
  3. this.brand = 'Benz';
  4. // return 123; //red
  5. // return 'string'; //red
  6. // return {}; //undefined
  7. // return []; //undefined
  8. // return function () { }; //undefined
  9. return function test() {
  10. console.log(1);
  11. }; //1
  12. }
  13. var car = new Car();
  14. console.log(car.color);
  15. console.log(car);

以上发现当return引用值的时候可以修改return结果,原始值则不能

bind/call/apply

  1. function test() {
  2. console.log('a');
  3. }
  4. //系统隐式调用call()
  5. test.call(); //a

call()apply()的作用:

  • 改变this的指向

写法:

被借用方法的函数名.call/apply(目标函数内部/this, 参数)

  1. function Car(brand, color) {
  2. this.brand = brand;
  3. this.color = color;
  4. this.run = function () {
  5. console.log('running');
  6. }
  7. }
  8. var newCar = {
  9. displacement: '2.5'
  10. };
  11. var newCar2 = {};
  12. //实现newCar有Car里所有的属性跟方法
  13. //Car.call(对象, 参数1, 参数2, ...)
  14. Car.call(newCar, 'benz', 'red');
  15. //Car.apply(对象, []) //arguments
  16. Car.apply(newCar2, ['benz', 'red']);
  17. console.log(newCar);
  18. //{displacement: "2.5", brand: "benz", color: "red", run: ƒ}
  19. console.log(newCar2);
  20. //{brand: "benz", color: "red"}
  21. //call()/apply()还不会影响已有属性和方法
  22. var car = new Car('mazda', 'grey');
  23. console.log(car);
  24. //Car {brand: "mazda", color: "grey"}

案例:计算器(借用方法)

多人协作

  1. function Compute() {
  2. this.plus = function (a, b) {
  3. console.log(a + b);
  4. }
  5. this.minus = function (a, b) {
  6. console.log(a - b);
  7. }
  8. }
  9. function FullCompute() {
  10. Compute.apply(this);
  11. this.mul = function (a, b) {
  12. console.log(a * b);
  13. }
  14. this.div = function (a, b) {
  15. console.log(a / b);
  16. }
  17. }
  18. //借用Compute里面的方法
  19. var compute = new FullCompute();
  20. compute.plus(1, 2); //3
  21. compute.minus(1, 2); //-1
  22. compute.mul(1, 2); //2
  23. compute.div(1, 2); //0.5

bindcall区别:

  • bind改变this指向后返回一个新的函数不执行
  • call/apply改变this指向并立即执行
  1. p1.play.call(p2,'男',20);
  2. p1.play.apply(p2,['男',20]);
  3. p1.play.bind(p2,'男',20)();
  4. //类似写法
  5. var fn = p1.play.bind(p2,'男',20);
  6. fn();

bind重写:

  1. //bind特性:
  2. //1.不执行
  3. //2.实例化时失效
  4. var p = {
  5. age: 18
  6. }
  7. function Person() {
  8. console.log(this);
  9. console.log(this.age);
  10. }
  11. //函数内部this默认指向window
  12. // Person(); window undefined
  13. //改变this指向为p对象
  14. // Person.call(p); {age: 18} 18
  15. // Person.apply(p); {age: 18} 18
  16. // Person.bind(p)(); {age: 18} 18
  17. //p对象并不是构造函数所以报错
  18. // var person = Person.call(p);
  19. // new person(); Uncaught TypeError: person is not a constructor
  20. //因为bind返回的是一个未执行的函数
  21. //所以实例化后bind失效了(new会生成自己的this)所以是undefined
  22. // var person = Person.bind(p);
  23. // new person();
  1. //重写bind
  2. var p = {
  3. age: 18
  4. }
  5. function Person(name1, name2) {
  6. console.log(this);
  7. console.log(this.age);
  8. console.log(name1, name2);
  9. }
  10. //更改this指向原理:其实是更改执行期上下文 context
  11. Function.prototype.myBind = function (context) {
  12. //2.但是函数内部this指向window,所以_self保存内部this指向
  13. var _self = this,
  14. //arguments -> context
  15. //从第1位(忽略第0位arguments)开始复制参数
  16. //返回一个数组 -> ['andy','lucy']
  17. args = Array.prototype.slice.call(arguments, 1),
  18. //利用圣杯模式解决同一引用被修改时影响结果
  19. temFn = function () {};
  20. /**
  21. console.log(_self);
  22. * ƒ Person() {
  23. * console.log(this);
  24. * console.log(this.age);
  25. * }
  26. */
  27. //3.传参问题:
  28. //如何实现两种写法?
  29. //写法一:
  30. //绑定时一起传参
  31. //Person.bind(p, 'andy');
  32. //写法二:
  33. //执行时才传参
  34. //var p = Person.bind(p, 'andy');
  35. //p('andy');
  36. //1.因为不执行,所以返回一个新的函数出去
  37. return function () {
  38. //找到该函数里所有的实参数组列表
  39. //newArgs 是空的数组
  40. var newArgs = Array.prototype.slice.call(arguments);
  41. // console.log(args, newArgs);
  42. // ['andy','lucy'] []
  43. // console.log(this, _self);
  44. //this -> 实例化的对象
  45. //_self -> 构造函数Person函数本身
  46. //参数1:执行期上下文传入
  47. //参数2:把新旧参数拼接一起,追加新传入的数组元素
  48. //如何实现实例化后bind失效的问题?
  49. //实现方法:为了使实例化对象this是构造函数构造出来的
  50. //原理:将实例化后的原型引用直接赋值给fn函数原型,并判断即可
  51. var fn = function () {
  52. //判断:实例化对象this是否构造函数构造出来的
  53. //那么:是的话实例化对象就为实例化对象,不是就为context上下文
  54. _self.apply(this instanceof _self ? this : context, args.concat(newArgs));
  55. }
  56. temFn.prototype = this.prototype;
  57. fn.prototype = new temFn();
  58. return fn;
  59. }
  60. }
  61. // Person.myBind()(); window undefined
  62. // Person.myBind(p)(); {age: 18} 18
  63. // var p = Person.bind(p, 'andy', 'lucy')(); andy lucy

链式调用

实现链式调用

  1. var sched = {
  2. wakeup: function () {
  3. console.log('Running');
  4. //this -> sched
  5. return this;
  6. },
  7. morning: function () {
  8. console.log('Going shopping');
  9. return this;
  10. },
  11. noon: function () {
  12. console.log('Having a rest');
  13. return this;
  14. },
  15. afternoon: function () {
  16. console.log('Studying');
  17. return this;
  18. },
  19. evening: function () {
  20. console.log('walking');
  21. return this;
  22. },
  23. night: function () {
  24. console.log('Sleeping');
  25. return this;
  26. }
  27. }
  28. sched.wakeup().morning().noon().afternoon().evening().night()

generator&iterator

7种数组遍历的方法:

  • forEach() 普通的数组遍历方法 for
  • map() 映射 -> 每一次遍历,返回一个数组元素 -> 返回一个新的数组
  • filter() 过滤 -> 每一次遍历返回布尔值来决定当前元素是否纳入新的数组中
  • reduce() 归纳 -> 每一次遍历将当前元素收归到容器中
  • reduceRight() -> reduce的反向操作
  • every()-> 判定是否所有元素都符合条件
  • some() -> 是否有某一个或多个符合一个条件

遍历底层实现:

for循环,遍历就是一次性对数组中每一个元素进行查询和处理

希望遍历的过程是可以控制的(遍历的过程可停止,也可继续),手动的控制遍历流程,这种方式就叫做迭代的过程。

产品迭代 -> 人为控制的产品升级与扩展 -> munally control

生成器和迭代器:

  • 生成器是一个函数
  • 迭代器是由生成器函数执行后返回的一个带有next方法的对象
  • 生成器对迭代的控制是由yield关键字来执行的

写法一:

  1. function* generator() {
  2. //第一次遍历
  3. yield '姓名: 大田';
  4. yield '年龄: 30';
  5. yield '爱好: 旅游';
  6. return '我爱JavaScript';
  7. }
  8. //执行
  9. const iterator = generator();
  10. console.log(iterator.next()); //{value: "姓名: 大田", done: false}
  11. console.log(iterator.next()); //{value: "年龄: 30", done: false}
  12. console.log(iterator.next()); //{value: "爱好: 旅游", done: false}
  13. console.log(iterator.next()); //{value: "我爱JavaScript", done: true}

执行next()方法生成一个对象就是第一个yeild出来的结果

每一次yeild都产出一个迭代的一个对象,迭代对象包含valuedone属性 遍历过程结束

写法二:

  1. const arr = ['姓名: 大田', '年龄: 30', '爱好: 旅游'];
  2. //生成器函数
  3. function* gen(arr) {
  4. for (var i = 0; i < arr.length; i++) {
  5. yield arr[i];
  6. }
  7. return '我爱JavaScript';
  8. }
  9. //执行
  10. const iterator = gen(arr);
  11. console.log(iterator.next()); //{value: "姓名: 大田", done: false}
  12. console.log(iterator.next()); //{value: "年龄: 30", done: false}
  13. console.log(iterator.next()); //{value: "爱好: 旅游", done: false}
  14. console.log(iterator.next()); //{value: "我爱JavaScript", done: true}

迭代会遍历的区别是:

迭代会把每次的遍历都拆分出来,着就是迭代的过程

写一个迭代函数

  1. function gen(arr) {
  2. var nextIndex = 0;
  3. return {
  4. next: function () {
  5. //正常迭代 or 迭代完成
  6. //arr[nextIndex ++] 先取值后加1
  7. return nextIndex < arr.length ? {
  8. value: arr[nextIndex++],
  9. done: false
  10. } : {
  11. value: arr[nextIndex++],
  12. done: true
  13. }
  14. }
  15. }
  16. }

Arguments对象

函数内部对应参数值的实参列表,也是一个对象,内置的局部变量,本质是类数组对象。

类数组Array-like

  • 具有length属性
  • 具有从零开始的属性下标
  • 没有数组的内置方法
  • 非箭头函数的其他函数的内置的局部变量

越到ES6arguments越来越弱化

  1. function test(a, b, c) {
  2. /**
  3. * callee: 宿主函数 test
  4. * Sybal(Symbol.iterator): 可迭代对象标识
  5. */
  6. // //obj为不可迭代对象
  7. // var obj = {
  8. // a: 1,
  9. // b: 2,
  10. // c: 3
  11. // }
  12. // var it = generator(obj);
  13. // console.log(it.next()); //报错不是迭代对象
  14. console.log(arguments);
  15. console.log(arguments.toString()); //[object Arguments]
  16. //证明arguments不是数组
  17. console.log(Array.isArray(arguments)); //false
  18. console.log(arguments.callee);
  19. }
  20. test(1, 2, 3);

可迭代对象

  1. //写一个生成器函数
  2. function* generator(args) {
  3. for (var v of args) {
  4. //产出v
  5. yield v;
  6. }
  7. }
  8. var it = generator(arguments);
  9. console.log(it.next()); //{value: 1, done: false}

非箭头函数的其他函数的内置的局部变量

  1. var test = () => {
  2. console.log(arguments);
  3. }
  4. test();
  5. //Uncaught ReferenceError: arguments is not defined
  6. //箭头函数把arguments抛弃了
  7. //取而代之的是...args
  8. var test2 = (...args) => {
  9. console.log(args);
  10. }
  11. test2(1, 2, 3); //[1, 2, 3]

arguments泄漏:将arguments类数组变为数组

  1. //将arguments类数组变为数组
  2. function test() {
  3. // slice()返回一个新的数组
  4. var argArr = [].slice.call(arguments);
  5. console.log(argArr);
  6. }
  7. test(1, 2, 3); //[1, 2, 3]

形参实参的对应关系

  1. //形参实参的对应关系
  2. function test(a) {
  3. /**
  4. * 形式参默认情况下是会有共享关系
  5. */
  6. // arguments[0] = 10;
  7. // console.log(a); //10
  8. // console.log(arguments[0]); //10
  9. a = 100;
  10. console.log();
  11. console.log(a); //100
  12. console.log(arguments[0]); //100
  13. }
  14. test(1);
  15. //形参种但凡有一个参数有默认值,arguments都不会对应跟踪参数最终的值
  16. function test2(a = 100) {
  17. arguments[0] = 10;
  18. console.log(a); //1
  19. console.log(arguments[0]); //10
  20. }
  21. test2(1);