ZYB ARTICLES REPOS

JavaScript学习总结

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript

变量


// 声明变量 
var data;


// 多个变量 
var age = 18,
    year = 19999;

// 只声明不赋值
var age;
console.log(age); // undefined

// 不声明不赋值
console.log(xx); // Uncaught ReferenceError: xx iis not defined

// 不声明,直接赋值
page = 1;
console.log(page); // 可以正常输出1


如果在函数内部没有声明直接赋值的变量属于全局变量

// num1 num3都是全局变量
var num1 = 1;
function fn() {
  var num2 = 2;
  num3 = 3;
}

console.log(num1);
console.log(num2);
console.log(num3);

数据类型

js的变量数据类型只有在程序的运行过程中,根据赋值号右边的值来确定

// 类型可变 
var x = 6;
x = '6';

// 简单数据类型
// Number String Boolean Undefined Null

// Number
var age = 21;
var PI = 3.1415926;

var bNum = 0b10; // 二进制
var oNum = 0123; // 八进制 
var hNum = 0xABC; // 十进制

// Number型的最大值和最小值
console.log(Number.MAX_VALUE);  // 1.7976931348623157e+308
console.log(Number.MIN_VALUE);  // 5e-324

// 无空大
console.log(Infinity);

// 无穷小
console.log(-Infinity);

// Not a Number
console.log(NaN);
// "adfas" - 12; 这就是NaN
// 但 “123” - 12 和 '123' - 12不是,会计算出111

// 判断是否是非数字: isNaN()
// isNaN("123") 和  isNaN(123)  返回的都是false


// String
var s1 = "string_type_1";
var s2 = 'string_type_2'; // js推荐用单引号,因为HTML用双引号

// 字符串长度(不是函数)
s1.length;

// 字符串拼接
var s3 = "123" + 12; // 输出"12312"这一点与"123"-12非常不同需要注意

// Boolean
// true
// false


// Undefined
var ud1;
var ud2 = undefined;

console.log(ud1 + 'haha'); // 输出 undefinedhaha
console.log(ud2 + 1); // 输出NaN


// Null
var null1 = null;

console.log(null1 + "haha");  // 输出: nullhaha
console.log(null1 + 1); // 输出:1

// 复杂数据类型
// Object

检测数据类型: typeof


var num = 10;
console.log(typeof num); // number

var str = 'hello'
console.log(typeof str); // string

var bool = false;
console.log(typeof bool); // boolean

// 这里特别注意null是object类型
var null1 = null;
console.log(typeof null1); // object

数据类型转换

// 转换为字符串类型
// 方法1: toString()
var num1 = 10;
var str1 = num1.toString();

// 方法2: String()强制类型转换
var str2 = String(num1);

// 方法3: 加号拼接字符串,又称隐式转换
var str3 = num + '';


// 转换为数字型
// 方法1: parseInt() parseFloat()
var str1 = "123";
var num1 = parseInt(str1);

// parseInt会向下取整
parseInt("3.14"); // 3
parseInt("2.72"); // 2

// parseInt自动去掉尾部
parseInt("120px"); // 120
parseInt("F120px"); // NaN

// 方法2: Number强制类型转换

// 方法3: 利用 - * / > < >= <= 隐式转换 
console.log('12' - 0);
console.log('12' - '10');


// 转换为Boolean
// 代表空、否定的值会被转换成false;其余的被转换为true
// 以下全为false
Boolean('');
Boolean(0);
Boolean(NaN);
Boolean(undefined);
Boolean(null);

// 以下全为true
Boolean(123);
Boolean('null');


比较运算符全等:=== !==要求全部数据类型一致

switch-case隐式用的是全等方式

console.log(37 == '37'); // true
console.log(37 === '37'); // false

分支-循环

数组

声明方法


// 数组有两种创建方式
// 方法1: 利用数组字面量创建
var arr1 = [1, 2, 3, 4, 5];

// 方法2: 利用 new创建数组
var arr2 = new Array();

// 数组内的类型不一定要一样
var arr3 = [1, "2"];

// 空数组
var arr4 = [];

// 访问不存在的下标返回undefined

添加元素

// 数组元素个数: 数组名.length
// length属性不仅可读,还可写

// 方法1
var arr1 = Array();
arr1.length = 3;
console.log(arr1); // [empty x 3], 每个元素都是undefined

// 方法2:
var arr2 = [1, 2];
arr2[4] = 5; // 追加
// [
//     1,
//     2,
//     null,
//     null,
//     5
// ]

判断是否为数组: if(arr instanceof Array){}Array.isArray(arr)

添加删除:

返回数组元素索引号: indexOf,不存在则返回-1

var arr = ['red', 'green', 'blue', 'green'];
console.log(arr.indexOf('green')); // 只返回1
console.log(arr.lastIndexOf('green')); //只返回3

数组转字符串: toString()join('分隔符')

遍历数组


var arr = [1, 2, 3, 4, 6];
arr.forEach(function(value){
  console.log(value);
});

// obj就是arr
arr.forEach(function(value, index, obj){
  console.log(value, index, obj);
});

函数

函数有两种声明方式


// 方式1:
function fn() {
  // ...
}

// 方式2: 匿名函数 
var fn = function {
  // ...
}

函数如果没有return则返回的是一个undefined

利用arguments实现不定参数


function fn() {
  console.log(arguments);
}
fn(1, 2, 3);

// 返回
// {
//     "0": 1,
//     "1": 2,
//     "2": 3
// }

arguments是一个伪数组:

  1. 具有length属性
  2. 按索引方式存储数据
  3. 不具有数组的pushpop等方法

对象 Object

创建对象的方法

1. 利用对象字面量

var emptyObj = {};
var objA = {
  name: 'namexx',
  age: 120,
  sayHi: function() {
    console.log('hi~');
  }
}
// 使用方法
objA.name;
objA['age'];

2. 利用new Object

var emptyObj = new Object();
var objA = new Object();
objA.name = 'sdfasd';
objA.age = 119;
objA.sayHi = function() {
  console.log("hi~~~");
}

3. 利用构造函数

上面的方法一次只能创建一个对象

构造函数是一种特殊的函数,主要用来初始化对象,它总与new运算符一起使用。可以把类中一些公共属性和方法抽象出来,封装到构造函数里。

function 构造函数名() {
  this.属性 = 值;
  this.方法 = function() {
    // ...
  }
}

new 构造函数名();
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHi = function() {
    // ...
  }

  // 构造函数不需要return
}

var p = new Person('asdf', 34);
console.log(typeof p); // object

遍历对象

for (var k in p) {
  console.log(k); // 得到属性名
  console.log(obj[k]); // 得到属性值
}

箭头函数

箭头函数总体来说是一种函数的省略形式

基本语法

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
//相当于:(param1, param2, …, paramN) =>{ return expression; }

// 当只有一个参数时,圆括号是可选的:
(singleParam) => { statements }
singleParam => { statements }

// 没有参数的函数应该写成一对圆括号。
() => { statements }

=>相当于两个部分的综合

  1. function: =>前的参数列表之前相当于存在一个function关键字
  2. return: =>后的函数体相当于处于return关键字之后

以下两个代码效果一样,相当于省略了关键字function

var inx = 0;
array.forEach(function () { console.log(inx++); });
var inx = 0;
array.forEach(() => { console.log(inx++); });

对于=>含有return功能体现如下:

var inx = 0;
array.forEach(function () {
  var fn = () => inx++;
  console.log(fn());
});

输出

0
1
2
3

如果只有一个参数,可以省略括号

var array = ["Apple", "Tencent", "Google", "Meta"];
array.forEach(element => {
  console.log(element);
});

如果只有一个语句,可以省略花括号

var array = ["Apple", "Tencent", "Google", "Meta"];
array.forEach(element => console.log(element));

如果没有参数,或有多个参数,则括号不能省略

Promise

Promise接收一个名为executor的函数参数。

形式定义如:executor: (resolve: (value: any) => void, reject: (reason?: any) => void) => void

也就是说,executer接收两个函数参数resolvereject

在使用Promise时需要注意的是,**executer是同步执行的,在executer内可以启动一个异步任务。

var p = new Promise((resolve, reject) => {
  console.log("enter promise");
  setTimeout(() => {
    console.log("timeout");
    if (Math.random() < 0.5) {
      resolve("< 0.5");
    } else {
      reject(">= 0.5");
    }
  }, 1000);
  console.log("exit promise");
}).then(
  value => console.log("value: ", value),
  reason => console.log("reason: ", reason)
);

console.log("after promise");

以上代码的时序如下:

enter promise
exit promise
after promise
timeout
value:  < 0.5  或 reason:  >= 0.5

上述代码与如下等价

var p = new Promise((resolve, reject) => {
  console.log("enter promise");
  setTimeout(() => {
    console.log("timeout");
    if (Math.random() < 0.5) {
      resolve("< 0.5");
    } else {
      reject(">= 0.5");
    }
  }, 1000);
  console.log("exit promise");
})
  .then(value => console.log("value: ", value))
  .catch(reason => console.log("reason: ", reason)
  );

console.log("after promise");

如果在executer内部不启动异步任务的话:

var p = new Promise((resolve, reject) => {
  console.log("enter promise");
  if (Math.random() < 0.5) {
    resolve("< 0.5");
  } else {
    reject(">= 0.5");
  }
  console.log("exit promise");
}).then(
  value => console.log("value: ", value),
  reason => console.log("reason: ", reason)
);

console.log("after promise");

时序如下

enter promise
exit promise
after promise
value:  < 0.5  或 reason:  >= 0.5

async/await

async关键字能定义一个异步函数,该函数返回一个Promise对象

function asyncFunction1() {
  console.log("in asyncFunction1");
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("resolved");
    }, 1000);
  }).then(value => console.log("resolved: ", value));
}

async function asyncTest() {
  console.log("enter asyncTest");
  asyncFunction1();
  console.log("exit asyncTest");
}

console.log("before call asyncTest");
asyncTest();
console.log("after call asyncTest");

输出如下:

before call asyncTest
enter asyncTest
in asyncFunction1
exit asyncTest
after call asyncTest
resolved:  resolved

如果在调用asyncFunction1前加一个await关键字,则会一直等到asyncFunction1的异步任务执行完成

function asyncFunction1() {
  console.log("in asyncFunction1");
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("resolved");
    }, 1000);
  }).then(value => console.log("resolved: ", value));
}

async function asyncTest() {
  console.log("enter asyncTest");
  await asyncFunction1();
  console.log("exit asyncTest");
}

console.log("before call asyncTest");
asyncTest();
console.log("after call asyncTest");

输出如下:

before call asyncTest
enter asyncTest
in asyncFunction1
after call asyncTest  // 这意味着asyncTest是被异步执行的
resolved:  resolved
exit asyncTest        // 这意味着await是等到了asyncFunction1里的异步任务结束

捕获结果

resolve的结果可以直接拿到,reject的结果可以用try/catch的方式捕获。

function asyncFunction1() {
  console.log("in asyncFunction1");
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("timeout");
      if (Math.random() < 0.5) {
        resolve("< 0.5");
      } else {
        reject(">= 0.5");
      }
    }, 1000);
  })
}

async function asyncTest() {
  console.log("enter asyncTest");
  try {
    result = await asyncFunction1();
    console.log("result: ", result);
  } catch (e) {
    console.log("exception: ", e);
  }
  console.log("exit asyncTest");
}

console.log("before call asyncTest");
asyncTest();
console.log("after call asyncTest");

有两种输出可能

可能一:

before call asyncTest
enter asyncTest
in asyncFunction1
after call asyncTest
timeout
result:  < 0.5
exit asyncTest

可能二:

before call asyncTest
enter asyncTest
in asyncFunction1
after call asyncTest
timeout
exception:  >= 0.5
exit asyncTest

async定义的函数一般用来执行网络需要很长时间的操作?

await的存在大概就是可以在异步函数(async function)里可以按同步的方式等待异步调用返回结果。

事件对象

事件对象属性、方法 说明
e.target 触发事件的对象
e.type 事件的类型,比如click、mouseover[不带on]
e.preventDefault() 该方法阻止默认事件,比如不让链接跳转
e.stopPropagation() 该方法阻止事件流冒泡

其它

innerTextinnerHTML

innerHTML是W3C标准,innerText不是。