背景
- 1991年,李爵士发明 www
- 1992年,同事发明 CSS
- 1993年,创建 W3C
- 1995年,网景浏览器 Netscape —> Navigator 脚本
- Branden Eich JS 之父,推出 Mocha 脚本语言,看起来像 Java
语言的转变 Mocha —> LiveScript —> JavaScript
这个时候 Unicode UTF-8 发布,这个时候 JS 已经有 bug 了,主要在于编码方面的
1996年, MS IE 想要抢占浏览器市场,发明 JScript
- ECMAScript (申报标准)<—-网景开源 —-> firefox
- IE5.5 MS推出 JS发请求
- 2004年, Gmail 网页上的程序
- 后端—>前端 Front-end(以 JS 为生)
- 2010年左右,中国开始逐渐有前端开发这类职位
然而,JS 这个时候
- 全局变量(没有模块化)
- 标准化(内置代码少)
这个时候 ECMAScript 进行一次代码升级 从 ES3 —> ES5(ES4 死了),但是步子太小
Rails 社区 Ruby —> CoffeeScript JS 改良版
添加了 类、箭头函数、opiond chain 语法
ECMAScript6 步子合适,JS 终于成为一个现代编程语言
数据类型
JS 一共有 7 种数据类型
- 数字/字符串/布尔/symbol(符号)/null/undefined/对象
- 即 number/string/boolean/symbol/null/undefined/object(array,function…)
- 所以你看,”JS 一切皆对象” 这句话严格意义上来说是错的
number
十进制1 // 1
1.1 // 1.1
.1 // 0.1
1.23e2 // 123
二进制(以 0b 开头)0b11 // 3
八进制(0 开头)011 // 9
十六进制(0x 开头)0x11 // 17
字符串(String)
'你好' "你好" '' ""(空字符串) |
转义符号 “\” 用于多行字符串(不是字符串里有回车)var s = '12345 \ // 坑人语法
67890'
var s2 = '12345' + //好读的语法
'67890'
var s3 = '12345 ' (这里有空格) // 而这里有报错
'67890'
因为上面,所以 ES 6 做了升级处理,如下// 注意这里是反引号
// 这里也是包含有回车的
var s4 = ` 12345
67890`
布尔(boolean)
- true
- false
- && 与
- || 或
symbol
symbol 来源
symbol 就是那个对象全局的唯一的值,这其实很像数据库中的唯一识别 id,这个唯一识别的 id 对应一条完整的数据
而这个是用来干嘛的,简单来说就是这个值是用来标识一个对象的属性的,好了,为什么需要标识这个对象的属性呢?
想像一下你需要用别人提供的一个对象,然后你想在这个对象里面加个方法,但是假设你加的方法名跟对象里面的方法名一样,就会对原有对象方法进行了
修改,这样就污染了原对象。那么能不能有一种机制来起到报警/提示/避免的作用呢? 有,ES6 就引入了这种新的原始数据类型叫 symbol
理解 symbol
引入 symbol 前class person {
constructor(options) {
this.name = options.name;
this.age = options.age;
}
getAge() {
return this.age;
}
}
let xxx = new person({
name: 'xxx',
age: 1
});
xxx.getAge() // 1
const GetAge = { // mixin
getAge() { console.log('xxx'); }
}
// 这里就修改了原对象方法
Object.assign(person.prototype, GetAge);
xxx.getAge() // 'xxx'
引入 symbol 后let getAge = Symbol();
class person {
constructor(options) {
this.name = options.name;
this.age = options.age;
}
[getAge]() {
return this.age;
}
}
let xxx = new person({
name: 'xxx',
age: 1
});
xxx[getAge]() // 1
// let getAge = Symbol(); // 报错 重复定义
getAge = Symbol();
const GetAge = { // mixin
[getAge]() { console.log('xxx'); }
}
// getAge 是一个新的 Symbol 值,所以这里就没有覆盖掉以前的
Object.assign(person.prototype, GetAge);
xxx[getAge]() // 'xxx'
symbol 实例
假如有一个函数是这样的function test(type) {
switch(type) {
case 'xxx':
console.log('1');
break;
}
}
现在调用它var demo = {
xxx: 'xxx',
yyy: 'yyy'
}
test('xxx'); // '1'
// 或者
test(demo.xxx); // '1'
但是这么做不好,因为字符串可能有些有拼写错误会造成一些 bug,可以这么改function test(type) {
switch(type) {
case type.xxx:
console.log('1');
break;
}
}
var demo = {
xxx: 'xxx',
yyy: 'yyy'
}
test(demo.xxx); // '1'
但是我们发现,此时不管 demo.xxx
里的值为何值它都是会执行 console.log('1')
demo.xxx = 'demo';
test(demo.xxx); // '1'
只要不冲突,那干什么都行的话,那为什么不用 Symbol ???var demo = {
xxx: Symbol(),
yyy: Symbol()
}
test(demo.xxx); // '1'
另外需要强调的是,Symbol 可以创建一个独一无二的值,但它并不是字符串!!!
也可以给 Symbol 传参,但是这个只是起到一个’注释’的作用,如下var a1 = Symbol('a');
var a2 = Symbol('a');
a1 === a2; // false
console.log(a1); // Symbol(a)
console.log(a2); // Symbol(a)
null 与 undefined
如果一个值为 null 或者 undefined 则它都表示什么也没有,这也是 JS 的原创 bug
区别:
i.(规范)如果一个变量没有被赋值,那么这个变量的值就是 undefined
ii.(大家都认为)如果你想表示一个没有赋值的 String/Number/Boolean/Symbol,就用 undefined
iii.(大家都认为)如果你想表示一个没有赋值的对象,就用 null
object
前面说的都是基本类型或者说是简单类型,而 object 是复杂类型,但是所谓的复杂类型也是由简单类型组成的var name = 'frank'
var age = 18
var gender = 'male'
var person = {
'name': 'frank',
'age': 18,
'gender': 'male'
}
语法
// 声明定义
var person = {
name: 'frank',
age: '18',
self: person,
'': 'frank', // 这个是可以成立的
9a: 'frank', // 这样写不行
'9a': 'frank', // 这样是行的
'a b': 'frank', // 这样也是可以的
'中文': 'frank',// 中文是可以的
// 如果不加引号,那么就 按照标识符来判断是否符合语法
}
// 调用
person['name']
// 下面的语法成立么
person.self.self.self.self.name
// 调用空字符串成立
person['']
其他操作符
typeof
xxx 的类型 | string | number | boolean | null | undefined | symbol | object | function |
---|---|---|---|---|---|---|---|---|
typeof xxx | ‘string’ | ‘number’ | ‘boolean’ | ‘object’ | ‘undefined’ | ‘symbol’ | ‘object’ | ‘function’ |
delete
delete 操作符用来删除对象的某个属性,若没有指向这个属性的引用,那它最终会被释放var Employee = {
age: 28,
name: 'abc',
designation: 'developer'
}
console.log(delete Employee.name); // returns true
console.log(delete Employee.age); // returns true
// 当试着删除一个不存在的属性时
// 同样会返回true
console.log(delete Employee.salary); // returns true
in
若指定的属性在其指定的对象或原型链中,则 in 运算符返回 true// 数组
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees // 返回true
3 in trees // 返回true
6 in trees // 返回false
"bay" in trees // 返回false (必须使用索引号,而不是数组元素的值)
"length" in trees // 返回true (length是一个数组属性)
Symbol.iterator in trees // 返回true (数组可迭代,只在ES2015+上有效)
// 内置对象
"PI" in Math // 返回true
// 自定义对象
var mycar = {make: "Honda", model: "Accord", year: 1998};
"make" in mycar // 返回true
"model" in mycar // 返回true
for in
for…in 语句可以以任意顺序遍历一个对象的可枚举属性,对于每个不同的属性,语句都会执行var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
// Output:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"
for of
for…of 语句在可迭代的对象 (array, string, map, set…) 上创建一个迭代循环,也是为不同的属性值执行语句let iterable = [10, 20, 30];
for (let value of iterable) {
value += 1;
console.log(value);
}
// 11
// 21
// 31
for in 和 for of 的区别
首先,上代码!Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
let iterable = [3, 5, 7];
iterable.foo = 'hello';
for (let i in iterable) {
console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // logs 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i); // logs 3, 5, 7
}
上面代码我们可以看到区别了
- ‘hello’ 3 5 7 这些是属性对应的值,它不是可枚举属性
-for in
在遍历对象时,若不加条件,它会一直沿着原型链遍历这个对象新加的可枚举属性
-for of
在遍历对象时,它会遍历该对象定义的迭代值,而不是任何对象的属性