淘先锋技术网

首页 1 2 3 4 5 6 7

ECMAScript

客户端脚本语言的标准

基本语法

与html结合方式

  1. 内部JS:

    • 标签体内容就是js代码

      <script text="text/javascript">
          // 内容
      </script>
      
  2. 外部JS:

    • 通过src属性引入外部的js文件

      <script text="text/javascript" src="location">
          // 内容
      </script>
      

注意:

  1. 可以定义在html页面的任何地方。但是定义的位置会影响执行顺序;
  2. 可以定义多个;
  3. 同一个标签不能同时引入外部 同时有内部的,这样的话只有外部的好使。

注释

  1. 单行注释://注释内容
  2. 多行注释:/注释内容/

数据类型

原始数据类型(基本数据类型)
number

数字类型,整数 / 小数 / NaN(not a number 一个不是数字的数字类型)

toFixed(x) 小数点后保留 x 位小数

问题 bug:

  • 浮点数精度不准

  • 小数点前 以及 小数点后 位数大于 16 会出现精度问题

    console.log(1000000000000001 + 1000000000000001) // 2000000000000002
    console.log(10000000000000001 + 10000000000000001) // 20000000000000000
    
    console.log(1.000000000000001 + 1.000000000000001) // 2.000000000000002
    console.log(1.0000000000000001 + 1.0000000000000001) // 2
    

在这里插入图片描述

string

字符串类型,字符串 “abc” “a” ‘abc’

boolean

布尔类型,true 和 false

  1. null:一个对象为空的占位符
  2. undefined:未定义。如果一个变量没有给初始化值,则会被默认赋值为undefined

存放在 里,规则 先进后出

引用数据类型
  1. Array:数组。

  2. Object:对象。

  3. function:函数。

存放在 里,拷贝的是地址

变量

概念

一小块存储数据的内存空间

强弱类型

Java语言是强类型语言,而JavaScript是弱类型语言。

  • 强类型:在开辟变量存储空间时,定义了空间将来存储的数据的数据类型。只能存储固定类型的数据
  • 弱类型:在开辟变量存储空间时,不定义空间将来的存储数据类型,可以存放任意类型的数据。
全局&局部变量

访问规则

  • 里面的可以访问到外面的,外面的不能访问里面的
定义语法
var 变量名 = 初始化值;

// 定义多个遍历并赋值
var a = 10,
    b = 20,
    c = 30,
    d = 40,
    e;
document.write(a,b,c,d,e);
命名规则
  1. 变量名必须以英文字母、_ 、$ 开头;
  2. 变量名可以包括英文字母、_ 、$ 、数字;
  3. 不可以用系统的关键字、保留字作为变量名。
typeof 操作符

获取变量的类型。

number string boolean object undefined function

console.log(typeof(123)); // number
console.log(typeof("123")); // string
console.log(typeof(true)); // boolean

用法:

  • typeof(值)
  • typeof 值

注:

  1. null、array 运算后得到的是object

  2. typeof() 返回的值是字符串类型

特殊:

变量不定义就使用必定会报错,只有一种情况下不会

自定义 type 方法:区分所有类别

function type(target) {
    var ret = typeof(target);
    var template = {
        "[object Array]" : "array",
        "[object Object]" : "object",
        "[object Number]" : "number - object",
        "[object Boolean]" : "boolean - object",
        "[object String]" : "string - object"
    }
    if (target === null) {
        return "null";
    } else if (ret == "object") {
        var str = Object.prototype.toString.call(target);
        return template[str];
    } else {
        return ret;
    }
}

类型转换

隐式类型转换
isNaN()
console.log(isNaN(NaN)); // true
console.log(isNaN(123)); // false
console.log(isNaN("123")); // false
console.log(isNaN("abc")); // true
console.log(isNaN(null)); // false
console.log(isNaN(undefined)); // true

isNaN() 之前会先 Number()

模拟 isNaN() 方法:

function myIsNaN(num) {
    var ret = Number(num);
    ret += "";
    if (ret == "NaN") {
        return true;
    } else {
        return false;
    }
}
++ – + -

(自增 自减 正负号)

var a = "123";
a ++; // 124
var a = +"123"; // +123
var b = +"abc"; // NaN
+

(加号)

两侧没有字符串,则正常数字相加,调用 Number() 方法将不是 number 的隐式转换

当加号两侧至少有一侧是字符串时,会调用 String() 方法把两侧均转换为字符串

当加号左侧是引用类型值时,调用的是 String() 方法隐式转换

[] + 1;  // --> String([]) + 1 --> "1"
[] + ""; // ""
{} + 1;  // 1

但引用值的隐式类型转换不用知道,规则较多。

- * / %

(运算符号)

调用 Number() 方法

var num = "2" * "1"; // number : 2
var num = "a" * "1"; // number : NaN
&& || !

判断调用 Boolean() 方法

< > …

(比较符号)

var a = 3 > "2"; // boolean: true
var a = "3" > "2"; // 会比较对应的 ASCII码 值

特殊

undefined > 0; // false 不转换,系统规定 undefined 和 null 不能和数进行比较
null > 0; // false
== !=

调用 Boolean() 方法

引用值比较的是地址:

{} == {}; // false
[] == []; // false

var obj = {};
var obj1 = obj;
obj == obj1; // true
obj === obj1; // true

特殊:

undefined == null; // true
NaN == NaN; // false
显式类型转换
Number()

把里面的东西转换为数字型

null false => 0

undefined => NaN

parseInt()

把里面的数转换为整数

注:看到非数字位截止

parseInt("123"); // 123
parseInt("123abc"); // 123
// 用途
// 把像素值从 100px 中取出来

parseInt(值, radix) radix: 2 - 36

后面的第二个参数表示此数所表示的进制

后面填 0

  • 有的浏览器是 原样转换整型输出
  • 有的是输出 NaN
parseFloat()

注:看到除了第一个 . 的非数字位截止

Boolean()
toString()

语法:

var demo = 10
var str = demo.toString(); // "10
// 转换进制
var num = demo.toString(8); // 12

注:undefined 和 null 不能用 toSting() 方法

例子:

二进制 转 十六进制

var num = 10000;
var test = parseInt(num, 2);
console.log(test.toString(16)); // aa
不发生类型转换
=== !==

数值 和 类型 均相等才可

1 === 1; // true
1 === "1"; // false
1 !== "1"; // true
1 !== 1; // false

特殊:

练习
var str  = false + 1;
document.write(str); // 1
var demo = false == 1;
document.write(demo); // false
if (typeof(a) && -true + (+undefined) + "") {
    document.write('基础扎实!');
}
if (11 + "11" * 2 == 33) {
    document.write('基础扎实!');
}
!!" " + !!"" - !!false || document.write('你觉得能打印,你就是🐖');

运算符

一元运算符

只有一个运算数的运算符
++,-- , +(正号)

  • ++ --: 自增(自减)
    • ++(–) 在前,先自增(自减),再运算
    • ++(–) 在后,先运算,再自增(自减)
  • +(-):正负号

注意:在JS中,如果运算数不是运算符所要求的类型,那么js引擎会自动的将运算数进行类型转换

  • 其他类型转number:
    • string转number:按照字面值转换。如果字面值不是数字,则转为NaN(不是数字的数字)
    • boolean转number :true转为1,false转为0
算数运算符

​ + - * / %

注:

  1. 1/0 会得 Infinity(无穷)
  2. 1/0 会得 -Infinity
  3. 0/0 会得 NaN
赋值运算符

​ = += -= *= /= %=

比较运算符

​ < >= <= == ===(全等于)

比较方式:

  1. 类型相同:直接比较

    ​ 字符串:按照字典顺序比较。按位逐一比较,直到得出大小为止。即 ASCII码 值

  2. 类型不同:先进行类型转换,再比较

    ​ ===:全等于。在比较之前,先判断类型,如果类型不一样,则直接返回false

逻辑运算符

​ && || !

  • &&(与):先看第一个表达式转化为 boolean 值是否为真,结果为真,则依次往后看每个表达式转换为boolean值的结果,直到碰到结果为 false 的表达式,返回该表达式的值。

    用法:(短路语句)

    var data = ...;
    // data && 执行一个语句,会用到data;
    data && fn(data);
    
  • ||(或):碰到表达式的结果 boolean值为真则返回该表达式的值

    用法:(兼容)

    div.onclick = function (e) {
        // 兼容 IE 浏览器
        var event = e || window.event;
    }
    
  • ! (非):将表达式的值转换为 boolean值 再取反,返回该 boolean值。

    var a = !!"";
    // !! 可以让一个值转换为 boolean值
    

注意:

undefined、null、NaN、""、0、false ==> false

除了以上六个值以外,其他的转换为 boolean 类型均为 true

练习:

(window.foo || (window.foo = 'bar'));
// window.foo = 'bar'
// 先读小括号内的,即先赋值
三元运算符

语法:

判断表达式的值,如果是 true 则取值1,如果是 false 则取值2;

逗号运算符

会将后面的结果返回出去

var a = (1 - 1, 1 + 1);
a --> 2
括号运算符
  1. 优先运算

    将里面的内容变为表达式

    (function () {}) 函数声明失效,变为表达式

  2. 立即执行

    (function () {})()

流程控制语句

  1. if…else…

    if(判断语句) {
        条件体
    }
    
  2. switch:

  • 在java中,switch语句可以接受的数据类型: byte int shor char,枚举(1.5) ,String(1.7)

  • 在JS中,switch语句可以接受任意的原始数据类型

    switch () {
        case 判断条件1:
        	执行语句1; break;
        case 判断条件2:
        	执行语句2; break;
        case 判断条件3:
            执行语句3; break;
        ...
        default:
            break;
    }
    
  1. while

    底层机制就是 for 循环:for 循环括号内两边不写语句就是 while 循环:for (;条件语句;) {}

    while(条件语句) {
        循环语句
    }
    
  2. do…while

    先执行一次,再判断条件语句

    do {
        循环体
    } while (条件语句)
    
  3. for

  4. break

    跳出循环或者 switch

  5. continue

    终止本次循环进行下次循环

JS特殊语法

  1. 语句以 ; 结尾,如果一行只有一条语句则 ; 可以省略 (不建议)
  2. 变量的定义使用 var 关键字,也可以不使用
  • 用:定义的变量是局部变量
  • 不用:定义的变量是全局变量(不建议)
  1. 练习:99乘法表
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>99乘法表</title>
        <style>
            td{
                border: 1px solid;
            }
        </style>

        <script>

            document.write("<table  align='center'>");
            //1.完成基本的for循环嵌套,展示乘法表
            for (var i = 1; i <= 9 ; i++) {
                document.write("<tr>");
                for (var j = 1; j <=i ; j++) {
                    document.write("<td>");

                    //输出  1 * 1 = 1
                    document.write(i + " * " + j + " = " + ( i*j) +"&nbsp;&nbsp;&nbsp;");

                    document.write("</td>");
                }
                /*//输出换行
document.write("<br>");*/

                document.write("</tr>");
            }

            //2.完成表格嵌套
            document.write("</table>");

        </script>
    </head>
    <body>

    </body>
</html>

基本对象

包装类

使用包装类对象创建的以下三种对象,依然还带有原本的数据类型的特点,不同在于可以有属性和方法

但是 undefined 和 null 不可以设置属性

Number:数字对象
String:字符串对象
Boolean:布尔对象
详解

原始数据类型不能有自己的属性和方法

自定义属性

但下面这个却不报错:

var num = 4;
num.len = 3; // 不报错
console.log(num.len) // undefined

原因:(包装类)

var num = 4;
num.len = 3; // 不报错
// new Number(4).len = 3;
// delete
// new Number(4).len --> undefined
console.log(num.len) // undefined
length问题

在数组中:

var arr = [1, 2, 3, 4, 5];
// arr.length --> 5
arr.length = 2
// arr.length --> 2
// arr --> [1, 2]

但是,在字符串中

var str = 'abcd';
// str.length --> 4
str.length = 2;
// new String('abcd').length = 2;
// delete
console.log(str); // abcd
// new String('abcd').length
console.log(str.length); // 4

字符串对象 本身就有 length属性,调用时是从包装类对象中返回的属性值

例题
var str = 'abc';
str += 1;
var test = typeof str; // test --> 'string'
if (test.length == 6) {
    test.sign = 'typeof的返回结果可能为String';
    // new String(test).sign = 'xxx';
}
// new String(test).sign
console.log(test.sign);

Function:函数对象

高内聚,弱耦合

创建
var fn = new Function(形式参数列表,方法体)//忘掉吧

// 函数声明
function 方法名称(形式参数列表) {
    方法体
}

// 命名函数表达式
var 方法名 = function abc() {
    方法体
}
// 匿名函数表达式 --- 函数表达式
var 方法名 = function() {
    方法体
}
参数
// 形式参数(形参)
function sum(a, b) {
    var c = a + b;
    document.write(c);
}
// 实际参数(实参)
sum(1, 2); // 3

参数不限制位数

arguments

表示实参列表,也有一些属性

  • arguments.length 实参个数

  • arguments.callee 指向这个函数自身引用 --> 即函数本身

    var num = (function (n) {
        if (n == 1) {
            return 1;
        }
        return n * arguments.callee(n - 1);
    }(100))
    

函数名.length 形参个数

function sum(a) {
    // arguments -- [11,2,3] 实参列表
	console.log(arguments); // [11,2,3]
    console.log(arguments.length); // 3
    // 函数名.length -- 形参长度
    concole.log(sum.length); // 1
}
sum(11, 2,3)

例子:

// 求不定参数个数的和
function sum() {
    var result = 0
    for (let i = 0; i < arguments.length; i++) {
        result += arguments[i];
    }
    document.write(result);
}
sum(1,3);

arguments里面的值 和 形参的值 之间有映射关系,但只是在形参和实参对应时才生效

function sum(a, b) {
    // arguments  -->  [1]
    a = 2;
    console.log(arguments[0]); // 2
    arguments[0] = 3;
    console.log(a); // 3
    
    b = 2;
    console.log(arguments[1]); // undefined
}
sum(1);
caller

函数的一个属性:表示被调用的环境

function test() {
    demo();
}
function demo() {
    demo,caller; // --> test --> function test() {demo();}
}
test();

不怎么用,但会和 arguments.callee 一块出现做区分

特点
  1. 方法定义时,形参的类型不用写,返回值类型也不写
  2. 方法时一个对象,如果定义名称相同的方法,会覆盖
  3. 在JS中,方法的调用只与方法的名称有关,和参数列表无关
  4. 在方法声明中有一个隐藏的内置对象(数组),arguments,封装所有的实际参数
调用
连续调用

模拟 jQuery 连续调用

var deng = {
    smoke : function () {
        console.log('Somking...');
        return this;
    },
    drink : function () {
        console.log('Drinking...');
        return this;
    },
    perm : function () {
        console.log('Perming...');
        return this;
    }            
}

deng.smoke().drink().perm();
结束条件和返回值
  • return 语句后的内容将不再执行,终止函数
  • 返回值
function myNumber(target) {
    return +target;
}
var num = myNumber('123');
console.log(typeof(num) + " " + num); // number 123
练习
求阶乘
// 求阶乘方法
// n! = n * (n-1)!
function mul(n) {
    if (n == 1 || n == 0) {
        return 1
    }
    return n * mul(n - 1);
}
var n = parseInt(prompt('input'));
mul(n);
// 递归
/* 
	mul(5);
    5 * mul(4);
    5 * 4 * mul(3);
    5 * 4 * 3 * mul(2);
    5 * 4 * 3 * 2 * 1; 
*/
斐波那契数列
// 斐波那契数列
// fb(n) == fb(n - 1) + fb(n - 2)
function fb(n) {
    if (n == 2 || n == 1) {
        return 1;
    }
    return fb(n - 1) + fb(n - 2);
}
原型 prototype

原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该圆心的属性和方法。原型也是对象。

Person.prototype.LastName = "Agoni";
function Person() {
    
}
var person = new Person();
var person1 = new Person();
// person.LastName --> "Agoni"
// person1.LastName --> "Agoni"

对象中固定不变的属性(公有的内容)可以提取出来放到原型中,避免代码多次执行造成冗余。

增删改查

经过了 var 给 window 上增加的属性为不可配置性属性,delete无法删除。

增改查

设置属性(可以多个一起设置)

Person.prototype = {
    height: 1400,
    lang, 4900,
    carName: "BMW"
}

Person.prototype.name = "" 的区别:

  • 上面的那一种是重新放一个空间,如之前已设置过且已经生成了对象,则 __proto__ 所指向的还是原先的那个空间;
  • 下面的是在原先的空间中设置或修改属性,使得 __proto__ 的访问数据变更
构造器 constructor
function Car() {}
var car = new Car();
// car.constructor --> funciton Car() {}

function Person() {}
Car.prototype = {
    constructor : Person
}
// car.constructor --> function Person() {}
__proto__

隐式属性 __proto__ 内就放着原型,在控制台展开可以查看

原理:

Person.prototype.name = "abc";
funciton Person() {
    // var this = {
    //     __proto__ : Person.prototype
	// }
}
var person = new Person();

原型也可以改变:

// 代码接上一部分
var obj = {
    name: "sunny"
}
var person = new Person();
// person.name --> "abc"
Person.__proto__ = obj;
// person.name --> "sunny"
原型链
Grand.prototype.lastName = "agoni";
funciton Grand() {
    
}
var grand = new Grand();

Father.prototype = grand;
function Father() {
    this.name = "Lay"
}
var father = new Father();

Son.prototype = fatehr;
function Son() {
    this.hobbit = "smoke"
}
var son = new Son();
// son.hobbit --> "smoke"
// son.name --> "Lay"
// son.lastName --> "Agoni"

查找属性,依照 son --> father --> grand 顺序依次查找,这个链就叫 原型链。

链顶并不是最末的:

Object.prototype

绝大多数对象的最终原型

// Grand.prototype.__proto__  -->  Object.prototype

// son.toString() --> function toString() { [native code] } // 最终终端的方法

// Object.prototype.__proto__  -->  null

Object.prototype 里面没有 __proto__ 了

Object.create()

括号内填原型:只能是 对象 或 null

Person.prototype.name = "sunny";
function Person() {
    
}
var person = Object.create(Person.prototype)

特殊点:

原型最终不会指向 Object.prototype

var obj = Object.create(null);
// obj.toString() --> 访问不到,报错

语法:

Object.create(prototype, definedProperty<特性>)

方法重写
Person.prototype = {
    toString : function () {
        return 'hehe';
    }
}
function Person() {
    
}
var person = new Person();
// person.toString(); --> "hehe"

发生截断,不会访问到终端 Object.prototype 的 toSting() 方法

Number Array Boolean String 都对 toSting() 方法进行了重写

document.write 原理

会隐式调用 toSting() 方法

var obj = Object.create(null);
document.write(obj); // 报错,因为自己创建的对象值为 null 且 Object.create() 创建的没有原型链,没有 toString() 方法,所以报错

obj.toStirng = function () {
    return 'AgoniLay';
}
document.write(obj); // AgoniLay --> 调用了 AgoniLay 方法
call/apply
call()

call 带参数

根本作用:改变 tihs 指向

function Person(name, age) {
    this.name = name;
    this.age = age;
}
var person = new Person('deng', 100);

var obj = {
    
}
// 第一个参数指 this 的指向,之后的依次代表 实参 对应 形参
Person.call(obj, 'agoni', 19);
// obj --> {name: 'agoni', age: 19}

使用实例:

function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name, age, sex, tel, grade) {
    Person.call(this, name, age, sex);
    this.tel = tel;
    this.grade = grade;
}

var student = new Student('sunny', 123, 'male', 1309, 2017);
function Wheel(wheelSize, style) {
    this.style = style;
    this.wheelSize = wheelSize;
}
function Sit(c, sitColor) {
    this.c = c;
    this.sitColor = sitColor;
}
function Model(height, width, len) {
    this.height = height;
    this.width = width;
    this.len = len;
}
function Car(wheelSize, style, c, sitColor, height, width, len) {
    Wheel.call(this, wheelSize, style);
    Sit.call(this, c, sitColor);
    Model.call(this, height, width, len);
}
var car = new Car(100, '花里胡哨', '真皮', 'red', 1800, 1900, 4900);
// car {style: "花里胡哨", wheelSize: 100, c: "真皮", sitColor: "red", height: 1800, …}
apply()

和 call() 区别:

  • 传参列表不同:apply 第一个参数还是 this 所指对象,第二个参数是一个数组,数组里面是所有的实参
    • call 需要把实参按照形参的个数传进去
    • apply 需要传一个 arguments
function Car(wheelSize, style, c, sitColor, height, width, len) {
    Wheel.apply(this, [wheelSize, style]);
    Sit.call(this, [c, sitColor]);
    Model.call(this, [height, width, len]);
}
继承 --> 圣杯模式
  1. 传统形式 --> 原型链

    • 过多的继承了没用的属性
  2. 借用构造函数 call()/apply()

    • 不能继承借用构造函数的原型
    • 每次构造函数都要多走一个函数(视觉上减少代码,但多走了方法)
  3. 共享原型

    son.prototype = father.prototype

    Father.prototype.lastName = "AgoniLay"
    function Father() {
    }
    function Son() {
    }
    funciton inherit(Target, Origin) {
        Target.prototype = Origin.prototype;
    }
    // 先继承,后用
    inherit(Son, Father);
    
    var son = new Son();
    // son.lastName --> "AgoniLay"
    // father.lastName --> "AgoniLay"
    
    Son.prototype.sex = "male"; // 添加后,son 和 father 都有了这个属性
    // son.sex --> "male"
    // father.sex --> "male"
    
  4. 圣杯模式 *

    // 通俗写法
    function inherit(Target, Origin) {
        function F() {};
        // 以下两行顺序不能颠倒
        F.prototype = Origin.prototype;
        Target.prototype = new F();
        // 优化
        Target.prototype.constuctor = Target;
        Target.prototype.uber = Origin.prototype;
    }
    
    Father.prototype.lastName = "AgoniLay"
    function Father() {
    }
    function Son() {
    }
    
    inherit(Son, Father);
    var son = new Son();
    var father = new Father();
    // father.lastName --> "AgoniLay"
    // son.lastName --> "AgoniLay"
    
    Son.prototype.sex = "male";
    // son.sex --> "male"
    // father.sex --> undifined
    
    // 雅虎的
    var inherit = (function () {
        var F = function () {}; // 闭包应用 -- 私有化变量
        return function (Target, Origin) {
            F.prototype = Origin.prototype;
            Target.prototype = new F();
            Target.prototype.constructor = Target;
            Target.prototype.uber = Origin.prototype;
        }
    }());
    

Array:数组对象

创建
  1. var arr = []; 数组字面量 – 推荐使用

    var arr = [1,2,3];
    
    var arr = [,,]; // [undefined * 2]
    var arr = [1,,2]; // [1, undefined, 2] --> 稀松数组
    
  2. var arr = new Array();

    和 数组字面量 区别:

    // 只传一个参数,代表数组的长度
    var arr = new Array(10); // [undefined * 10]
    // 但不能只传一个小数
    var arr = new Array(10.2); // 报错
    
读和写

溢出读是 undefined,可以溢出写

var arr[1,2,3];
arr[0] = 2 // [2,2,3]
console.log(arr[10]); // undefined 不会报错
arr[10] = "aa"; // 可以添加 --> [1,2,3,undefined * 7,"aa"]
方法

可以改变原数组的方法开始:只有七个

push()

在数组最后添加数据,不仅可以添加一个,返回值是添加后的数组长度

// 自己写 push() 方法
var arr = [];
Array.prototype.push = function () {
    for(var i = 0; i < arguments.length; i ++) {
        this[this.length] = arguments[i];
    }
    return this.length;
}
arr.push(1,2,3); // 3 --> [1,2,3]

但 push 的原理是取决于属性中 length 值,与 length 值有关

pop()

把数组的最后一位剪切出来返回

unshift()

在数组开头添加数据,不仅可以添加一个,返回值是添加后的数组长度

shift()

把数组的第一位剪切出来返回

reverse()

把数组逆转,把原数组返回

splice()

arr.splice(从第几位开始, 截取多少的长度, 在切口处添加新的数据)

返回截取的数组

var arr = [1,1,2,2,3,3];
arr.splice(1,2); // [1,2] --> [1,2,3,3]

var arr = [1,1,2,2,3,3];
arr.splice(1,2,0,0,0) // [1,2] --> [1,0,0,0,2,3,3]

var arr = [1,2,3,4];
// 不截取,只是向中间插入数据 例:向上面数组 3 后面添加一个 0
arr.splice(3,0,0);

var arr = [1,2,3,4];
// 截取的位置可以是负数,表示从倒数开始
arr.splice(-1,1); // [4] --> [1,2,3]
// 实现
splice = function (pos, ...) {
    pos += pos > 0 ? 0 : this.length; // -1 + 4 = 3
}
sort() *

在原数组上将原数组内元素升序排列(但并不是数字值的大小)

var arr = [1,3,4,0,-1,9];
arr.sort(); // [-1,0,1,3,4,9]
// 降序
arr.sort().reverse();

为了解决这个问题,sort 留了一个接口让用户自定义排序方式

规则:

  1. 必须写俩形参
  2. 看返回值
    1. 当返回值为负数时,那么前面的数放在前面
    2. 为正数,那么后面的数在前
    3. 为 0,不动
var arr = [1,3,5,4,10];
// 传参顺序 1,3  1,5  1,4  1,10  3,5
arr.sort(function (a, b) {
    // 函数体
    // if (a > b) {
    //    return 1;
    //} else {
    //    return -1;
    //}
    // 简化
    return a - b; // 升序
    // return b - a; // 降序
}) // [1, 3, 4, 5, 10]

运用:

给一个有序的数组,乱序

var arr = [1,2,3,4,5,6,7];
arr.sort(function () {
	return Math.random() - 0.5;
})

给一个对象数组,按某一属性排

var cheng = {
    name : "cheng",
    age : 30,
}
var deng = {
    name : "deng",
    age : 60,
}
var zhang = {
    name : "zhang",
    age : 19,
}
var arr = [cheng, deng, zhang];
// 按年龄升序排列
arr.sort(function (a, b) {
    return a.age - b.age;
}) // ["zhang", "cheng", "deng"]

按字符串长度排序

var arr = ['as', 'asdad', 's', 'sjdfhakjsdfhlkajsd', 'asdjhajsk'];
arr.sort(function (a, b) {
    return a.length - b.length;
}) // ['s', 'as', 'asdad', 'asdjhajsk', 'sjdfhakjsdfhlkajsd']

按字节长度排序

function retBytes(str) {
    var num = str.length;
    for(var i = 0; i < str.length; i ++) {
        if (str.charCodeAt(i) > 255) {
            num++;
        }
    }
    return num++;
}

var arr = ['赛的环境asdj', 'asd', '啥的, 爱睡觉的', 'a saa'];
arr.sort(function (a, b) {
    return retBytes(a) - retBytes(b);
}) // ["asd", "a saa", "赛的环境asdj", "啥的, 爱睡觉的"]

不改变原数组的方法开始:调用完使用 变量 接收,否则没有意义

concat()

把括号内的数组拼接到前面数组的后面,不在原数组上修改,返回拼接后的数组

toString()

将数组返回为字符串类型的字符串

slice()

arr.slice('从该位开始截取', '截取到该位')

arr.slice(1) 从第 1 位截取,截取到最后,也可以填负数(规则 + length)

arr.slice() 整个截取

join()

将数组中元素按规定连接起来,返回一个字符串

参数可以传所有原始值,但最好传字符串

var arr = [1,2,3];
arr.join("&"); // "1&2&3"
arr.join(); // "1,2,3"
split()

是字符串的方法,是 join() 的可逆方法

var str = "1-2-3-4-5";
str.split("-"); // ["1", "2", "3", "4", "5"]

自定义方法:

unique()
Array.prototype.unique = function (arr) {
    var temp = {};
    var arr = [];
    var len = this.length;
    for (var i = 0; i < len; i++) {
        if (!temp[this[i]]) {
            temp[this[i]] = 'agoni';
            arr.push(this[i]);
        }
    }
    return arr;
}
类数组

类数组有要求:

  1. 属性要为索引(数组)属性
  2. 必须有 length 属性