ECMA基础(五)

函数基础

数学的函数:

  1. //x, y 任意x有确定的y 与之对应
  2. //x自变量
  3. //y -> x
  4. //y = f(x) x => 参数/定义域 y => 函数的值域 => 函数值是确定的

计算机的函数:

  1. //函数式编程
  2. function test(a, b, c) {
  3. //执行语句
  4. }

高内聚低耦合概念

耦合问题:代码块里有重复高的代码

让一个功能体(代码块)具有强功能性和高独立性

-> 模块的单一责任制(独立完成功能且不依赖其他模块)

高内聚

模块有独立的功能

低耦合

重复代码抽象化

函数的作用

解耦有很多基于函数的方式

  1. //解耦合 -> 最好的方式是函数
  2. if (3 > 0) {
  3. for (var i = 0; i < 10; i++){
  4. console.log(i);
  5. }
  6. }
  7. if (2 > 0) {
  8. for (var i = 0; i < 10; i++){
  9. console.log(i);
  10. }
  11. }
  12. if (1 > 0) {
  13. for (var i = 0; i < 10; i++){
  14. console.log(i);
  15. }
  16. }
  17. //如何解耦
  18. function test() {
  19. for (var i = 0; i < 10; i++){
  20. console.log(i);
  21. }
  22. }
  23. if (3 > 0) {
  24. test();
  25. }
  26. if (2 > 0) {
  27. test();
  28. }
  29. if (1 > 0) {
  30. test();
  31. }

函数基本写法

函数声明

  1. //引用值 声明函数的关键字
  2. function test(参数) {
  3. //函数的执行语句;
  4. }
  5. test();

函数只有被调用的时候才会执行

函数名的命名规则

  • 不能数字开头
  • 可以以字母,下划线,$开头
  • 可以包含数字
  • 小驼峰命名法,复合单词

函数种类

定义函数的方法

  • 函数声明
  • 函数表达式(字面量)

匿名函数

  1. function(){}

匿名函数表达式/函数字面量

  1. var test = function(){}

关于字面量:

  • 字符串:''
  • 对象:{}
  • 数组:[]
  • 函数:function(){}

函数的组成部分

  1. //function 关键字
  2. //函数名
  3. //参数 可选
  4. //返回值 可以没有返回值
  5. //默认系统加return
  6. function 函数名(参数) {}

形参实参

在函数调用的时候可以给变量赋值,外部可以通过参数给内部的变量赋值,当函数定义的时候参数是没有值的,仅仅是占位用的

形参

占位 -> 形式上占位 -> 形式参数 -> 形参

实参

当调用的时候,有实际参数的赋值

实际参数 -> 实参 -> 给占位符赋值

赋值的时候,参数都是一一对应的

  1. var a = Number(window.prompt('a'));
  2. var b = Number(window.prompt('b'));
  3. function test(a,b) {
  4. console.log(a + b);
  5. }
  6. test(a, b);
  • 实参参数数量 小于 形参参数数量 不报错且只打印实参数量,形参为undefined
  • 实参参数数量 大于 形参参数数量 不报错且只打印形参数量

函数内部其实是知道实参的个数

arguments参数

  1. function test(a, b) {
  2. for (var i = 0; i < arguments.length; i++){
  3. console.log(arguments[i]); //1 2 3
  4. }
  5. }
  6. test(1, 2, 3);

形参和实参的长度能否知道

  1. function test(a, b) {
  2. //形参长度
  3. console.log(test.length); //2
  4. //实参长度
  5. console.log(arguments.length); //3
  6. }
  7. test(1, 2, 3);

可以取实参的其中一位

  1. function test(a, b) {
  2. console.log(arguments[1]); //2
  3. }
  4. test(1, 2, 3);

实参求和:一个函数被调用时,累加他的实参值

  1. //问题:不知道实参有多少个
  2. function sum() {
  3. var a = 0;
  4. for (var i = 0; i < arguments.length; i++){
  5. a += arguments[i];
  6. }
  7. console.log(a);
  8. }
  9. sum(1, 2, 3, 4, 5); //15

函数内部是可以更改实参的值

  1. function test(a, b) {
  2. a = 3;
  3. console.log(arguments[0]); //3
  4. }
  5. test(1, 2);

若有实参传值函数内部可以修改实参的值,反之不能修改

  1. function test(a, b) {
  2. b = 3;
  3. console.log(arguments[1]); //undefined
  4. }
  5. test(1);

映射

无论实参如何赋值,形参都会跟着变,形参数组里必须有对应的值

如果实参和形参的对应关系是存在的,那么就存在必然的映射关系

  1. function test(a, b) {
  2. a = 3;
  3. console.log(arguments[0]); //3
  4. }
  5. test(1, 2);
  6. //test(1, 2) => test(3, 2);

return

函数内部return

  • 函数内部没有写returnJS引擎会默认隐式加上
  • 函数内部return下面的语句是不会执行的
  • return 后面接数据会返回相应的数据值
  1. function test(name) {
  2. //真 => name
  3. //假往后走找最后一位
  4. return name || '你没有输入名字';
  5. }
  6. // console.log(test('1111')); //1111
  7. console.log(test()); //'你没有输入名字'

变量类型

  • 全局变量
  • 局部变量

函数内部能访问外部变量

  1. b = 2;
  2. function test() {
  3. var a = 1;
  4. console.log(b); //2
  5. }
  6. test()

外部不能访问函数内部变量

  1. b = 2;
  2. function test() {
  3. var a = 1;
  4. console.log(b); //2
  5. }
  6. test()
  7. console.log(a); //报错 a not define
  8. console.log(typeof(a)); //undefined
  1. a = 1;
  2. function test1() {
  3. var b = 2;
  4. console.log(a); //1
  5. function test2() {
  6. var c = 3;
  7. console.log(b); //2
  8. }
  9. test2();
  10. console.log(c); //报错
  11. }
  12. test1()

每个函数都有自己独立的作用域

  1. function test1() {
  2. var a = 1;
  3. console.log(b); //报错
  4. }
  5. function test2() {
  6. var b = 2;
  7. console.log(a); //报错
  8. }
  9. test1();
  10. test2();

参数默认值

参数的默认值为undefined

  1. function test(a, b) {
  2. console.log(a); //1
  3. console.log(b); //undefined
  4. }
  5. test(1);

不传递实参的情况下初始默认值

  1. function test(a = 1, b = 2) {
  2. console.log(a); //1
  3. console.log(b); //2
  4. }
  5. test();

es6写法

function test(a = 1){}, es5且IE8不支持

保留第一个参数的默认值,更改另外的参数

关于形参a和实参arguments[0] 对应且存储的地方不同但具有映射关系

  • 选非undefined的数据
  • 形参实参都为undefined结果也是undefine
  1. function test(a = 1, b) {
  2. console.log(a); //1
  3. console.log(b); //2
  4. }
  5. test(undefined, 2);
  1. function test(a = undefined, b) {
  2. console.log(a); //1
  3. console.log(b); //2
  4. }
  5. test(1, 2);

es5版本的情况下初始化形参的默认值

写法一

  1. function test(a, b) {
  2. //实参1存在返回实参1,不存在返回1
  3. //实参2存在返回实参1,不存在返回2
  4. var a = arguments[0] || 1;
  5. var b = arguments[1] || 2;
  6. console.log(a + b);
  7. }
  8. test(); //3
  9. test(3, 4); //7

写法二

  1. function test(a, b) {
  2. var a, b;
  3. if (typeof (arguments[0]) !== 'undefined') {
  4. a = arguments[0];
  5. } else {
  6. a = 1;
  7. }
  8. if (typeof (arguments[1]) !== 'undefined') {
  9. b = arguments[1];
  10. } else {
  11. b = 2;
  12. }
  13. console.log(a + b);
  14. }
  15. test(); //3
  16. test(3, 4); //7

写法二可以用三元运算改写

  1. function test(a, b) {
  2. var a, b;
  3. typeof (arguments[0]) !== 'undefined' ? arguments[0] : a = 1;
  4. typeof (arguments[1]) !== 'undefined' ? arguments[1] : b = 2;
  5. console.log(a + b);
  6. }
  7. test(); //3
  8. test(3, 4); //7

递归

函数自己调用自己,要考虑性能问题

  • 找规律
  • 找出口

总结:总是走到出口的时候,再向上一步一步的赋值计算,然后返回结果

对象

  1. var teacher = {
  2. name: 'zhangsan',
  3. age: 32,
  4. sex: 'male',
  5. height: 176,
  6. weight: 160,
  7. teach: function () {
  8. console.log('I am teaching Java');
  9. },
  10. smoke: function () {
  11. console.log('I am smoking');
  12. },
  13. eat: function () {
  14. console.log('I am having a dinner');
  15. }
  16. }

对象创建

  • 字面量/直接量
  • 构造函数

对象的调用方式

  1. var myLang = {
  2. No1: 'HTML',
  3. No2: 'CSS',
  4. No3: 'JavaScript',
  5. myStudyingLang: function (num) {
  6. //myLang['No1'] -> this['No' + num]
  7. console.log(this['No' + num]);
  8. }
  9. }
  10. myLang.myStudyingLang(1); //HTML
  11. obj = {
  12. name: '123'
  13. }
  14. console.log(obj['name']); //123

字面量

  1. var obj = {
  2. name: 'zhangsan',
  3. sex: 'male'
  4. }
  5. obj.name = 'lisi';

构造函数,系统自带

  1. var obj = new Object();
  2. obj.name = 'lisi';
  3. obj.sex = 'male';
  4. console.log(obj);

执:

执行方法

  1. teacher.drink();

增:

属性增加

  1. teacher.address = 'beijing';

方法增加

  1. teacher.drink = 'I am drinking beer';

删:

移除属性

  1. delete teacher.address;

删除方法

  1. delete teacher.teach;

改:

属性更改

  1. teacher.height = 166;

查:

属性查找

  1. teacher.eat();

this

代表对象本身

案例:出勤

  1. var attendance = {
  2. students: [],
  3. total: 6,
  4. join: function (name) {
  5. this.students.push(name);
  6. if (this.students.length === this.total) {
  7. console.log(name + '到课,学生已到齐');
  8. } else {
  9. console.log(name + '到课,学生未到齐');
  10. }
  11. },
  12. leave: function (name) {
  13. //this.students.indexOf(name) => 数字元素索引
  14. //indexOf() = -1 => 不存在该数组元素
  15. //splice(index, 删除位数)
  16. var idx = this.students.indexOf(name);
  17. if (idx !== -1) {
  18. this.students.splice(idx, 1);
  19. }
  20. console.log(name + '早退了');
  21. console.log(this.students);
  22. },
  23. classOver: function () {
  24. this.students = [];
  25. console.log('已下课');
  26. }
  27. }
  28. attendance.join('zhangsan'); //["zhangsan"]
  29. attendance.join('lisi'); //["zhangsan", "lisi"]
  30. attendance.join('wangwu'); //["zhangsan", "lisi", "wangwu"]
  31. attendance.leave('lisi'); //["zhangsan", "wangwu"]
  32. attendance.classOver();

包装类

思考:数字和字符串是否有自己的属性和方法?

  1. var a = 1;
  2. var b = 'abc';
  3. a.len = 3;
  4. b.add = 'bcd';
  5. a.reduce = function () {}

原始值并没有自己的方法和属性

思考:数字是不是一定是原始值?

  1. var a = 1;
  2. console.log(a); //1
  3. var b = new Number(a);
  4. console.log(b); //Number {1}
  5. b.len = 1;
  6. console.log(b); //Number {1, len: 1}
  7. b.add = function () {
  8. console.log(1);
  9. }
  10. console.log(b); //Number {1, len: 1, add: ƒ}

能看出成为实例化对象后的数字对象,且可以设置属性和方法

  1. //对象 + 数字也能参与运算且运算结果变为原始值
  2. var a = 1;
  3. var b = new Number(a);
  4. b.len = 1;
  5. b.add = function () {
  6. console.log(1);
  7. }
  8. var c = 3;
  9. var d = b + 1;
  10. console.log(a + c); //4
  11. console.log(d); //2

经过包装参与的对象运算后又变为原始值

  1. var a = 1;
  2. console.log(a); //1
  3. var aa = new Number(1);
  4. console.log(aa); //Number {1}
  5. aa.name = 'aa';
  6. console.log(aa); //Number {1, name: "aa"}
  7. var bb = aa + 1;
  8. console.log(bb); //2
  9. console.log(aa); //Number {1, name: "aa"}

运算后又变回数字对象

系统内置的构造函数包装方法:

  • new Number()
  • new String()
  • new Boolean()

经过包装参与运算后又变为原始值

  1. var a = 'abc';
  2. console.log(a); //abc
  3. var aa = new String('abc');
  4. aa.name = 'aa';
  5. console.log(aa); //String {"abc", name: "aa"}
  6. var bb = aa + 'bcd';
  7. console.log(bb); //abcbcd
  1. var test = new Number(undefined);
  2. console.log(test); //Number {NaN}
  3. var test = new Number(null);
  4. console.log(test); //Number {0}
  5. var test = new String(undefined);
  6. console.log(test); //String {"undefined"}
  7. var test = new String(null);
  8. console.log(test); //String {"null"}

undefinednull是不可以设置任何的属性和方法

  1. console.log(undefined.length); //报错
  2. console.log(null.length); //报错

JavaScript包装类的过程

  1. var a = 123;
  2. a.len = 3;
  3. console.log(a.len); //undefined
  1. var str = 'abc';
  2. console.log(str.length); //3
  1. var a = 123;
  2. a.len = 3;
  3. //原始值没有属性和方法
  4. //JS判断:new Number(123).len = 3; => 无法保存 => delete
  5. /**
  6. * 相当于
  7. * var obj = {
  8. * name: 'obj'
  9. * }
  10. * console.log(obj); //{name: "obj"}
  11. * delete obj.name;
  12. * console.log(obj); //{}
  13. */
  14. console.log(a.len); //undefined
  1. var str = 'abc';
  2. console.log(str.length); //3
  3. console.log(new String(str).length); //3

数组截断arr.length

  1. var arr = [1, 2, 3, 4, 5];
  2. arr.length = 3;
  3. console.log(arr); //[1, 2, 3]
  4. arr.length = 6;
  5. console.log(arr); //[1, 2, 3, 4, 5, empty]

字符串截断

  1. var str = 'abc';
  2. str.length = 1;
  3. console.log(str); //abc
  4. //new String(str).length = 1 => 无法保存 => delete
  5. console.log(str.length); //3

笔试题

  1. var name = 'languiji';
  2. name += 10; //'languiji10'
  3. var type = typeof (name); //'string'
  4. if (type.length === 6) {
  5. type.text = 'string'; //new String(type).text = 'string' => 无法保存 => delete
  6. }
  7. console.log(type.text); //undefined

改造

  1. var name = 'languiji';
  2. name += 10;
  3. console.log(typeof (name)); //'string'
  4. var type = new String(typeof (name));
  5. console.log(type); //String {"string"}
  6. if (type.length === 6) {
  7. type.text = 'string';
  8. }
  9. console.log(type.text); //string

枚举

遍历数组

  1. //循环数组
  2. var arr = [1, 2, 3, 4, 5];
  3. //遍历过程
  4. for (var i = 0; i < arr.length; i++) {
  5. console.log(arr[i]);
  6. }
  1. //循环数组
  2. var arr = ['red', 'white', 'black', 'pink', 'blue'];
  3. //遍历过程
  4. for (var i in arr) {
  5. console.log(i); //0 1 2 3 4
  6. console.log(arr[i]); //red white black pink blue
  7. }

遍历对象

  1. //狭义的对象
  2. var car = {
  3. brand: 'Benz',
  4. color: 'red',
  5. displacement: '3.0',
  6. lang: '5',
  7. width: '2.5'
  8. }
  9. //key: 键名
  10. //car[key]: 键值
  11. for (var key in car) {
  12. console.log(key);
  13. //brand color displacement lang width
  14. console.log(car[key]);
  15. //JS引擎 car.key -> car['key'] -> undefined
  16. }

hasOwnProperty()

返回值:布尔值

作用于拷贝

for ... in遍历会遍历出所有对象包括原型上的属性

  1. function Car() {
  2. this.brand = 'Benz';
  3. this.color = 'red';
  4. this.displacement = '3.0';
  5. }
  6. Car.prototype = {
  7. lang: '5',
  8. width: '2.5'
  9. }
  10. Object.prototype.name = 'Object';
  11. var car = new Car();
  12. //遍历
  13. for (var key in car) {
  14. console.log(key + ': ' + car[key]);
  15. }
  16. /**
  17. * console.log(key + ': ' + car[key]);
  18. * brand: Benz
  19. * color: red
  20. * displacement: 3.0
  21. * lang: 5
  22. * width: 2.5
  23. * name: Object
  24. */

只想打印自定义属性而不是原型上的属性

  1. function Car() {
  2. this.brand = 'Benz';
  3. this.color = 'red';
  4. this.displacement = '3.0';
  5. }
  6. Car.prototype = {
  7. lang: '5',
  8. width: '2.5'
  9. }
  10. Object.prototype.name = 'Object';
  11. var car = new Car();
  12. //遍历
  13. for (var key in car) {
  14. if (car.hasOwnProperty(key)) {
  15. console.log(car[key]);
  16. }
  17. }
  18. /**
  19. * console.log(car[key]);
  20. * Benz
  21. * red
  22. * 3.0
  23. */

in

返回值:布尔值

判断属性是否存在于对象里

  1. var car = {
  2. brand: 'Benz',
  3. color: 'red'
  4. }
  5. //car['displacement']
  6. console.log('displacement' in car); //false
  1. //hasOwnProperty 排除原型
  2. //in 不排除原型
  3. function Car() {
  4. this.brand = 'Benz';
  5. this.color = 'red';
  6. }
  7. Car.prototype = {
  8. displacement: '3.0'
  9. }
  10. var car = new Car();
  11. console.log('displacement' in car); //true

instanceof()

返回值:布尔值

判断对象是否是构造函数实例化出来的

缺点:不能判断原始值

可以拿来判断数据类型(不推荐)

A对象的原型里到底有没有B的原型

  1. function Car() {}
  2. var car = new Car();
  3. console.log(car instanceof Car); //true
  4. console.log(car instanceof Object); //true
  5. function Person() {}
  6. var p = new Person();
  7. console.log(p instanceof Car); //false

在原型链上有重合的都为true

  1. console.log([] instanceof Array); //true
  2. console.log([] instanceof Object); //true
  3. console.log({} instanceof Object); //true

callee/caller

callee返回的是正在被执行的函数对象

  1. function test(a, b, c) {
  2. //callee返回的是正在被执行的函数对象
  3. //callee返回的是函数本身
  4. console.log(arguments.callee);
  5. //function test(a, b, c) {...}
  6. console.log(arguments.callee.length); //3
  7. }
  8. test(1, 2, 3);
  1. //arguments.callee.length函数本身形参的长度
  2. //test.length函数本身形参的长度
  3. //arguments.length实参的长度
  4. function test(a, b, c) {
  5. console.log(arguments.callee.length == test.length); //true
  6. console.log(arguments.callee.length === test.length); //true
  7. }
  8. test(1, 2, 3);

callee在哪个函数内部指向哪个函数

  1. function test1() {
  2. console.log(arguments.callee);
  3. function test2() {
  4. console.log(arguments.callee);
  5. }
  6. test2();
  7. }
  8. test1();

用递归的方式累加n位

  1. function sum(n) {
  2. if (n <= 1) {
  3. return 1;
  4. }
  5. //n + (n - 1)
  6. //10 + 9
  7. //10 + 9 + 8 ...
  8. return n + sum(n - 1);
  9. }
  10. var res = sum(10);
  11. console.log(res); //55

希望是一个自启动函数交给全局变量

  1. var sum = (function (n) {
  2. if (n <= 1) {
  3. return 1;
  4. }
  5. //此时找不到函数名
  6. //此时可以用callee
  7. return n + arguments.callee(n - 1);
  8. })(10);
  9. console.log(sum); //55

caller

调用当前函数的函数引用

返回调用所在的函数本身

  1. test1();
  2. function test1() {
  3. test2();
  4. }
  5. function test2() {
  6. //调用当前函数的函数引用
  7. //在哪个函数内部调用返回改函数本身
  8. console.log(test2.caller); //function test1() {...}
  9. }

严格模式报错

  1. 'use strict'; //报错
  2. test1();
  3. function test1() {
  4. test2();
  5. }
  6. function test2() {
  7. console.log(test2.caller);
  8. }

对象克隆

  1. var person1 = {
  2. name: 'zhangsan',
  3. age: 18,
  4. sex: 'male',
  5. height: 180,
  6. weight: 140
  7. }
  8. //希望拥有person1所有的属性和方法
  9. //person1的引用值地址赋值给了person2
  10. //person2修改属性的时候person1也会随之更改
  11. //因为他们指向同一的存储空间
  12. var person2 = person1;
  13. person2.name = 'lisi';
  14. console.log(person1);
  15. //{name: "lisi", age: 18, sex: "male", height: 180, weight: 140}
  16. console.log(person2);
  17. //{name: "lisi", age: 18, sex: "male", height: 180, weight: 140}

此时需要拷贝(赋值,克隆)

浅拷贝

  1. //如何克隆
  2. //循环:把属性添加到person2里
  3. //声明一个空对象不会指向同一个存储空间
  4. //浅拷贝
  5. var person2 = {};
  6. for (var key in person1) {
  7. //键值赋值
  8. //person1['name'] -> person1.name
  9. //循环的key刚好也是对象的键名
  10. //console.log(key);
  11. //console.log(person1[key]);
  12. person2[key] = person1[key];
  13. }
  14. person2.name = 'lisi';
  15. console.log(person1);
  16. console.log(person2);
  1. Object.prototype.num = 1;
  2. var person1 = {
  3. name: 'zhangsan',
  4. age: 18,
  5. sex: 'male',
  6. height: 180,
  7. weight: 140,
  8. son: {
  9. first: 'Jenney',
  10. second: 'Lucy',
  11. third: 'John'
  12. }
  13. }
  14. var person2 = {};
  15. for (var key in person1) {
  16. person2[key] = person1[key];
  17. }
  18. person2.name = 'lisi';
  19. person2.son.forth = 'Ben';
  20. console.log(person1);
  21. console.log(person2);
  22. /**
  23. * console.log(person1);
  24. * {name: "zhangsan", age: 18, sex: "male", height: 180, weight: 140, …}
  25. age: 18
  26. height: 180
  27. name: "zhangsan"
  28. sex: "male"
  29. son: {first: "Jenney", second: "Lucy", third: "John", forth: "Ben"}
  30. weight: 140
  31. __proto__: Object
  32. */
  33. /**
  34. * {name: "lisi", age: 18, sex: "male", height: 180, weight: 140, …}
  35. age: 18
  36. height: 180
  37. name: "lisi"
  38. num: 1
  39. sex: "male"
  40. son: {first: "Jenney", second: "Lucy", third: "John", forth: "Ben"}
  41. weight: 140
  42. __proto__: Object
  43. */

以上说明浅拷贝只遍历第一层结构的属性

写一个浅拷贝的函数

  1. function clone(origin, target) {
  2. //万一用户不传target参数,自己默认创建空对象
  3. var tar = target || {};
  4. for (var key in origin) {
  5. //排除原型上的属性
  6. if (origin.hasOwnProperty(key)) {
  7. tar[key] = origin[key];
  8. }
  9. }
  10. return tar;
  11. }
  12. var person2 = clone(person1);

深拷贝

如何深拷贝?

  1. //循环对象之前需要检测对象里面的属性值是否是引用值
  2. //当发现有引用值的时候需要遍历
  3. //不仅判断键值对是否含有引用值,还得判断是对象还是数组
  4. //利用递归克隆函数进行再次循环
  5. function deepClone(origin, target) {
  6. //万一用户不传target参数,自己默认创建空对象
  7. var target = target || {},
  8. toStr = Object.prototype.toString,
  9. arrType = '[object Array]';
  10. for (var key in origin) {
  11. //排除原型上的属性
  12. if (origin.hasOwnProperty(key)) {
  13. //判断是否为引用值 同时排除null
  14. if (typeof (origin[key]) === 'object' && origin[key] !== null) {
  15. //判断引用值是否为数组类型
  16. if (toStr.call(origin[key]) === arrType) {
  17. //创建空数组
  18. target[key] = [];
  19. } else {
  20. //引用值是对象
  21. //创建空对象
  22. target[key] = {};
  23. }
  24. //递归,再次遍历
  25. deepClone(origin[key], target[key]);
  26. } else {
  27. //这里是递归的出口
  28. //遍历第一层 浅拷贝
  29. target[key] = origin[key];
  30. }
  31. }
  32. }
  33. return target;
  34. }
  35. var person2 = deepClone(person1);

数组

数组字面量

  1. var arr = [];

内置构造函数(不推荐)

  1. var arr = new Array(); //[]

声明数组(不使用)

  1. var arr = Array(); //[]
  1. //数组
  2. arr = [1, 2, 3, 4, 5];
  3. console.log(arr.length); //5
  4. arr.push(9);
  5. console.log(arr); // [1, 2, 3, 4, 5, 9]

数组的原型Array prototype

所有数组都继承于Array.prototype,且里面所有的方法都可以继承和使用

  1. console.log(Array.prototype);

数组是什么?

  1. var obj1 = {};
  2. var obj2 = new Object();
  3. //通过系统内置的Object构造函数声明对象
  4. var obj3 = Object();
  5. console.log(obj1.__proto_); //Object prototype
  6. console.log(obj1.__proto_); //Object prototype
  7. console.log(obj1.__proto_); //Object prototype
  8. var arr = [1, 2, 3, 4, 5];
  9. //用对象模仿数组
  10. //index标记数组内部的元素即数组元素的下标(索引值)
  11. var obj = {
  12. 0: 1,
  13. 1: 2,
  14. 2: 3,
  15. 3: 4,
  16. 4: 5
  17. }
  18. //访问机制一样
  19. //obj1.name -> obj1['name']
  20. console.log(arr[2]); //3
  21. console.log(obj[2]); //3

实际上数组在JavaScript底层机制,就是继承对象而来,数组就是对象的另一种形式

数组截取

  1. //截取机制把最后的那位截取掉
  2. var arr2 = [, 1, 3, 5, 7, ];
  3. console.log(arr2); //[empty, 1, 3, 5, 7]
  4. console.log(arr2.length); //5

稀松数组

  1. var arr = [, , ];
  2. console.log(arr); //[empty × 2]
  3. console.log(arr.length); //2
  4. //稀松数组
  5. var arr3 = [, 1, 3, , , 5, 7, ];
  6. console.log(arr3); //[empty, 1, 3, empty × 2, 5, 7]

数组new Array传值

  1. var arr4 = new Array(, 1, 3, 4, 5, ); //报错语法错误
  2. var arr5 = new Array(1, 3, , , 4, 5); //报错语法错误
  3. var arr6 = new Array(1, 2, 3, 4, 5); //报错语法错误
  4. console.log(arr6); //[1, 2, 3, 4, 5]
  5. var arr1 = new Array(5);//[,,,,,] 传数字设置数组长度
  6. var arr1 = new Array(5.2); //报错非法的数组长度
  7. var arr1 = new Array('a'); //["a"]
  8. console.log(arr1); //[empty × 5]
  9. console.log(arr1.length); //5
  1. var arr = [1, 2, 3, 4, 5];
  2. // var arr = [1, 2, 3, 4, 5, empty];
  3. console.log(arr[5]); //undefined
  4. //为什么打印undefined
  5. var obj = {
  6. 0: 1,
  7. 1: 2,
  8. 2: 3,
  9. 3: 4,
  10. 4: 5
  11. }
  12. console.log(obj[5]); //undefined

写入/更改

  1. //arr写入
  2. var arr1 = [];
  3. arr1[3] = 'a';
  4. console.log(arr1); //[empty × 3, "a"]
  5. //arr更改元素
  6. arr1[2] = 'b';
  7. console.log(arr1); //[empty × 2, "b", "a"]

类数组

特点:

  • 具有length属性
  • 数组形式下标对应的值

arguments

  1. // 类数组
  2. arguments
  3. function test() {
  4. arguments.push(7);
  5. console.log(arguments); //报错
  6. }
  7. test(1, 2, 3, 4, 5);
  8. // 说明arguments没有继承Arr.prototype
  9. // 其实类数组是一个像数组的对象

HTML标签列表

  1. var oDiv = document.getElementsByTagName('div');
  2. console.log(oDiv); //[div, div, div]
  3. console.log(oDiv.push(7)); //报错

重写类数组

  1. //试写一个类数组
  2. //类数组原理
  3. var obj = {
  4. '0': 1,
  5. '1': 2,
  6. '2': 3,
  7. '3': 4,
  8. '4': 5,
  9. 'length': 5,
  10. //此属性可以把{}转为[]
  11. //继承splice方法
  12. 'splice': Array.prototype.splice
  13. }
  14. //把数组原型上的push方法挂载到对象原型上
  15. Object.prototype.push = Array.prototype.push;
  16. //重写push方法
  17. Array.prototype.push = function (elem) {
  18. //属性名=属性值
  19. //obj[obj.length] = elem;
  20. //obj[5] = elem;
  21. this[this.length] = elem;
  22. this.length++;
  23. }
  24. console.log(obj);
  25. //{0: 1, 1: 2, 2: 3, 3: 4, 4: 5, length: 5}
  26. //[1, 2, 3, 4, 5, splice: ƒ]
  1. //alibaba
  2. var obj = {
  3. '2': 3,
  4. '3': 4,
  5. 'length': 2,
  6. 'splice': Array.prototype.slice,
  7. 'push': Array.prototype.push
  8. }
  9. console.log(obj.push(1)); //3
  10. console.log(obj.push(2)); //4
  11. console.log(obj);
  12. /**
  13. * Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]
  14. 2: 1
  15. 3: 2
  16. length: 4
  17. push: ƒ push()
  18. splice: ƒ slice()
  19. __proto__: Object
  20. */
  21. //分析:
  22. obj[2] = 1;
  23. //obj[length] = push(1) -> length++ -> obj[2] = 1 -> 2: 1
  24. obj[3] = 2;
  25. //obj[length] = push(2) -> length++ -> obj[3] = 2 -> 3: 2
  1. var person = {
  2. //数组特性
  3. '0': '张晓一',
  4. '1': '张小三',
  5. '2': '张小三',
  6. //对象特性
  7. 'name': '张三',
  8. 'age': 32,
  9. 'weight': 140,
  10. 'height': 180,
  11. 'length': 3
  12. }
  13. Object.prototype.push = Array.prototype.push;
  14. Object.prototype.splice = Array.prototype.splice;
  15. console.log(person[1]); //张小三
  16. console.log(person.weight); //140
  17. console.log(person.length); //3
  18. console.log(person);
  19. //Object(3) ["张晓一", "张小三", "张小三", name: "张三", age: 32, weight: 140, height: 180]
  20. //对象的方式遍历
  21. for (var key in person) {
  22. //排除原型上的方法 push / splice
  23. if (person.hasOwnProperty(key)) {
  24. console.log(person[key]);
  25. //张晓一 张小二 张三 32 140 180 3
  26. }
  27. }

类数组转为数组

利用Array.prototype.slice.call(arguments))方法

  1. //类数组转数组
  2. //类数组没有slice(),push()方法
  3. function test() {
  4. console.log(arguments);
  5. console.log( Array.prototype.slice.call(arguments));
  6. }
  7. test(1, 2, 3, 4);
  8. /**
  9. * console.log(arguments):
  10. * Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  11. 0: 1
  12. 1: 2
  13. 2: 3
  14. 3: 4
  15. callee: ƒ test()
  16. length: 4
  17. Symbol(Symbol.iterator): ƒ values()
  18. __proto__: Object
  19. */
  20. /**
  21. * (4) [1, 2, 3, 4]
  22. 0: 1
  23. 1: 2
  24. 2: 3
  25. 3: 4
  26. length: 4
  27. __proto__: Array(0)
  28. */