美文网首页
JavaScript

JavaScript

作者: 张_何 | 来源:发表于2022-05-11 15:44 被阅读0次
ES6 和 JavaScript 的关系
  • ES6 全称ECMAScript 6.0, ECMA 是一个标准化组织,1996 年 11 月,JavaScript 的创造者 Netscape 公司,将 JavaScript 提交给标准化组织 ECMA,次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
    该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。
    因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。
    ES6 在 2015 年 6 月发布,以后每年 6 月分发布一个小的版本
  • json 全称:JavaScript Object Notation
  • 万维网: World Wide Web
  • JavaScript 是一种动态类型语言,也就是说,变量的类型没有限制,变量可以随时更改类型。
var a = 1;
a = 'hello';
  • 如果使用var重新声明一个已经存在的变量,是无效的。
var x = 1;
var x; // 这次是无效的
x // 1

但是,如果第二次声明的时候还进行了赋值,则会覆盖掉前面的值。

var x = 1;
var x = 2; //会覆盖前面的值 等同于 var x; x = 2;
  • JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
console.log(a);
var a = 1;

最后的结果是显示undefined,表示变量a已声明,但还未赋值。

  • 标识符:
    第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
    第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字0-9。
  • 注释:
    // 单行注释
    /* 块注释 */
    由于历史上 JavaScript 可以兼容 HTML 代码的注释,所以也被视为合法的单行注释。
x = 1; <!-- x = 2;
--> x = 3;

上面代码中,只有x = 1会执行,其他的部分都被注释掉了。需要注意的是,-->只有在行首,才会被当成单行注释,否则会当作正常的运算。

  • switch
    switch语句后面的表达式,与case语句后面的表示式比较运行结果时,采用的是严格相等运算符(===),而不是相等运算符(==),这意味着比较时不会发生类型转换。
var x = 1;

switch (x) {
  case true:
    console.log('x 发生类型转换');
    break;
  default:
    console.log('x 没有发生类型转换');
}

上面代码中,由于变量x没有发生类型转换,所以不会执行case true的情况。这表明,switch语句内部采用的是“严格相等运算符”

  • 标签:
    JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。
top:
  for (var i = 0; i < 3; i++){
    for (var j = 0; j < 3; j++){
      if (i === 1 && j === 1) break top;
      console.log('i=' + i + ', j=' + j);
    }
  }

上面代码为一个双重循环区块,break命令后面加上了top标签(注意,top不用加引号),满足条件时,直接跳出双层循环。如果break语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环。

top:
  for (var i = 0; i < 3; i++){
    for (var j = 0; j < 3; j++){
      if (i === 1 && j === 1) continue top;
      console.log('i=' + i + ', j=' + j);
    }
  }

上面代码中,continue命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue语句后面不使用标签,则只能进入下一轮的内层循环。

数据类型

  • JavaScript 的数据类型,共有六种:
  • 数值(number):整数和小数(比如1和3.14)。
  • 字符串(string):文本(比如Hello World)。
  • 布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)。
  • undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
  • null:表示空值,即此处的值为空。
    对象(object):各种值组成的集合。
  • ES6 又新增了第七种 Symbol 类型的值
获取变量类型
  • instanceof
  • Object.prototype.toString
  • typeof
if (typeof v === "number") {

}
  • null与undefined都可以表示“没有”,含义非常相似。将一个变量赋值为undefined或null,老实说,语法效果几乎没区别。相等运算符(==)甚至直接报告两者相等。在if语句中,它们都会被自动转为false。null 转化成数字时,自动变成 0,undefined 是一个表示此处无定义的原始值,转为数值时是 NaN。null表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。对象属性没有赋值为 undefined, 函数没有返回值默认返回 undefined

  • 布尔值:
    如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true。

  • undefined

  • null

  • false

  • 0

  • NaN

  • ""或''(空字符串)

数值
  • JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。
  • 由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3    // false
0.3 / 0.1   // 2.9999999999999996 
(0.3 - 0.2) === (0.2 - 0.1)     // false
  • 根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。

  • 第1位:符号位,0表示正数,1表示负数

  • 第2位到第12位(共11位):指数部分

  • 第13位到第64位(共52位):小数部分(即有效数字)

  • js 中有正零和负零, 两者是等价的只有在做分母时返回的值不相等

-0 === +0 // true
(-0).toString() // '0'
(+0).toString() // '0'
(1 / +0) === (1 / -0) // false ,这是因为除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的
NaN
  • NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
  • 要注意的是,NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
    typeof NaN // 'number'
  • NaN不等于任何值,包括它本身。 NaN === NaN // false
  • NaN在布尔运算时被当作false Boolean(NaN) // false
  • NaN与任何数(包括它自己)的运算,得到的都是NaN。NaN + 32 // NaN
Infinity
  • Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity
  • Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)Infinity > 1000 // true
  • Infinity与NaN比较,总是返回false。 Infinity > NaN
  • Infinity的四则运算,符合无穷的数学计算规则。5 * Infinity // Infinity
与数值相关的全局方法
  • parseInt方法用于将字符串转为整数。 parseInt('123') // 123
  • 如果parseInt的参数不是字符串,则会先转为字符串再转换。parseInt(1.23) // 1
  • 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15
  • 如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。parseInt('abc') // NaN

  • 如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。parseInt('0x10') // 16

  • parseFloat方法用于将一个字符串转为浮点数。

字符串

  • 如果要在单引号字符串的内部,使用单引号,就必须在内部的单引号前面加上反斜杠,用来转义。双引号字符串内部使用双引号,也是如此。
'Did she say \'Hello\'?'
// "Did she say 'Hello'?"

"Did she say \"Hello\"?"
// "Did she say "Hello"?"
  • 如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠,这样输出的时候还是一行。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错。
var longString = 'Long \
long \
long \
string';
  • js 不支持多行字符串,如果需要可以自己想办法解决
  • 字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。
var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"

s[1] = 'a'; // 尝试修改索引值为 1 的字符
s // "hello"
  • JavaScript 使用 Unicode 字符集,JavaScript 不仅以 Unicode 储存字符,还允许直接在程序中使用 Unicode 码点表示字符,即将字符写成\uxxxx的形式,
var f\u006F\u006F = 'abc';
foo // "abc"

对象

  • JS 的对象是一种无序的复合数据集合。
// key 加不加引号都可以
var obj = {
  foo: 'Hello',
  bar: 'World'
};
// 或
var obj = {
  'foo': 'Hello',
  'bar': 'World'
};
// 如果 key 是数值,会被自动转换为字符串
var obj = {
  1: 'a',
  3.2: 'b',
  1e2: true,
  1e-2: true,
  .234: true,
  0xFF: true
};
  • 值可以是任何数据类型,包括函数
  • 读/写属性的两种方式
var obj = {
  p: 'Hello World'
};
obj.p // "Hello World"
obj['p'] // "Hello World"

var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
  • 查看一个对象本身的所有属性,可以使用Object.keys方法 Object.keys(obj);
  • delete命令用于删除对象的属性,删除成功后返回true。delete obj.p // true
  • 属性是否存在:in 运算符
    in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。in运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。
var obj = { p: 1 };
'p' in obj // true
'toString' in obj /
  • 属性的遍历:for...in 循环
    需要注意两点:
  • 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
  • 它不仅遍历对象自身的属性,还遍历继承的属性。除非继承的属性被设置为不可遍历属性
    一般情况下,都是只想遍历对象自身的属性,所以使用for...in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下,某个属性是否为对象自身的属性。
var person = { name: '老张' };

for (var key in person) {
  if (person.hasOwnProperty(key)) {
    console.log(key);
  }
}
// name
  • with 语句:
    它的作用是操作同一个对象的多个属性时,提供一些书写的方便。
var obj = {
  p1: 1,
  p2: 2,
};
with (obj) {
  p1 = 4;
  p2 = 5;
}
// 等同于
obj.p1 = 4;
obj.p2 = 5;

函数

  • JavaScript 允许省略参数。
function f(a, b) {
  return a;
}

f(1, 2, 3) // 1
f(1) // 1
f()

f.length // 2 , 函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
  • 没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
function f(a, b) {
  return a;
}
f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined
  • JavaScript 允许函数有不定数目的参数,
var f = function (one) {
  console.log(arguments[0]);
  console.log(arguments[1]);
  console.log(arguments[2]);
}

f(1, 2, 3)
// 1
// 2
// 3

数组

  • 任何类型的数据,都可以放入数组,数组内的元素不必是统一类型的
  • 本质上,数组属于一种特殊的对象typeof [1, 2, 3] // "object",数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...)。
var arr = ['a', 'b', 'c'];
Object.keys(arr)
// ["0", "1", "2"] ,可以看到 arr 的健名是 0、1、2
  • 当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位(hole)。
var a = [1, , 1];
a.length // 3
  • 使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。

运算符

  • 指数运算符:x ** y
  • JavaScript 提供两种相等运算符:==和===。,它们的区别是相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为“同一个值”。如果两个值不是同一类型,严格相等运算符(===)直接返回false,而相等运算符(==)会将它们转换成同一个类型,再用严格相等运算符进行比较。
布尔运算符
  • 且运算符&&:
    如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。
't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""

if (i) {
  doSomething();
}
// 等价于
i && doSomething();
  • 或运算符 ||
    它的运算规则是:如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值。
't' || '' // "t"
't' || 'f' // "t"
'' || 'f' // "f"
'' || '' // ""
  • 全局变量:
    JavaScript 最大的语法缺点,可能就是全局变量对于任何一个代码块,都是可读可写。这对代码的模块化和重复使用,非常不利。
    因此,建议避免使用全局变量。如果不得不使用,可以考虑用大写字母表示变量名,这样更容易看出这是全局变量,比如UPPER_CASE。

  • 变量声明:
    JavaScript 会自动将变量声明“提升”(hoist)到代码块(block)的头部。

  • 建议不要使用相等运算符(==),只使用严格相等运算符(===)。

  • with可以减少代码的书写,但是会造成混淆。

console
  • 占位符:
    %s 字符串
    %d 整数
    %i 整数
    %f 浮点数
    %o 对象的链接
    %c CSS 格式字符串

  • console.warn() warn方法输出信息时,在最前面加一个黄色三角,表示警告;

  • console.error() error方法输出信息时,在最前面加一个红色的叉,表示出错

  • console.table() 方法可以将其转为表格显示

var languages = [
  { name: "JavaScript", fileExtension: ".js" },
  { name: "TypeScript", fileExtension: ".ts" },
  { name: "CoffeeScript", fileExtension: ".coffee" }
];
console.table(languages);

输出为:
(index) name fileExtension
0 "JavaScript" ".js"
1 "TypeScript" ".ts"
2 "CoffeeScript" ".coffee"

  • console.count() 方法用于计数,输出它被调用了多少次。
  • console.dir() 该方法对于输出 DOM 对象非常有用,因为会显示 DOM 对象的所有属性。
  • console.dirxml() 方法主要用于以目录树的形式,显示 DOM 节点。
  • console.assert() 方法主要用于程序运行过程中,进行条件判断,如果不满足条件,就显示一个错误,但不会中断程序执行。这样就相当于提示用户,内部状态不正确。它接受两个参数,第一个参数是表达式,第二个参数是字符串。只有当第一个参数为false,才会提示有错误,在控制台输出第二个参数,否则不会有任何结果。
  • console.time() 、console.timeEnd() 这两个方法用于计时,可以算出一个操作所花费的准确时间。

Object 对象

  • Object 构造函数: 可以接受一个参数,如果该参数是一个对象,则直接返回这个对象;如果是一个原始类型的值,则返回该值对应的包装对象

Object(value)与new Object(value)两者的语义是不同的,Object(value)表示将value转成一个对象,new Object(value)则表示新生成一个对象,它的值是value

  • Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名。Object.getOwnPropertyNames方法与Object.keys类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。
    对于一般的对象来说,Object.keys()和Object.getOwnPropertyNames()返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。Object.keys方法只返回可枚举的属性,Object.getOwnPropertyNames方法还返回不可枚举的属性名。

  • 属性描述对象:JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息,这些属性称为元属性。

{
  value: 123, // 是该属性的属性值,默认为undefined。
  writable: false, // 表示属性值(value)是否可改变(即是否可写),默认为true
  enumerable: true, // 表示该属性是否可遍历,默认为true。如果设为false,会使得某些操作(比如for...in循环、Object.keys())跳过该属性。
  configurable: false, // 表示属性的可配置性,默认为true。如果设为false,将阻止某些操作改写属性描述对象,比如无法删除该属性,也不得改变各种元属性(value属性除外)
  get: undefined, // 表示该属性的取值函数(getter),默认为undefined。
  set: undefined // 表示该属性的存值函数(setter),默认为undefined。
}
  • 创建对象一定要用 new 否则构造函数就会被当成普通函数调用,并不会生成实例对象

ES6

  • ES6 中使用关键字 new 创建对象时会默认执行 constructor 构造方法
  • constructor 中,子类必须通过 super 来调用父类的构造方法,对父类进行初始化,否则会报错
  • ES6 使用 extends 关键字来作为类的继承
ES6 的标签模板字符串
  • 标签模板字符串(Tagged Template Literals)。
  • 正常情况下,我们都是通过 函数名() 方式来进行调用的,其实函数还有另外一种调用方式:
  • 如果我们在调用的时候插入其他的变量:
  • 模板字符串被拆分了;
  • 第一个元素是数组,是被模块字符串拆分的字符串组合,如果以模块字符串结尾,那么会拆出一个空字符串
  • 后面的元素是一个个模块字符串传入的内容;
    比如如下我们定义一个接收可变参数的 test函数:
    function test(...args) {
      console.log(args);
    }

通常调用 test 函数时,是通过test("abc","bcd")调用的;
现在还有另一种调用方式就是通过标签模板字符串的方式,比如:

test`aaa`; // 输出 [["aaa"]]
const name = 'zhang';
const age = 18;
test`my name is ${name},age is ${age}`; // 输出[["my name is ", ",age is ", ""],"zhang",18], 这里以插入的${age}结尾, 所以第一个元素多了一个空字符串

相关文章

网友评论

      本文标题:JavaScript

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