讲义内容:JS 诞生的背景、基本类型、运算符java
如下内容只涉及 ES5 标准,ES6 增长的新内容能够在网上查找到。node
上世纪 90 年代网景公司开发的浏览器独步天下typescript
一个叫作 Brendan Eich 的工程师受命于开发一款脚本语言,来加强浏览器的功能。编程
这名工程师花费了 10 天时间设计出了第一个版本,名叫 LiveScript。数组
后来由于当时 Java 正红,公司将其更名为 JavaScript,因此 JS 和 Java 其实没有什么关系。浏览器
这名工程师在设计语言之初有几个目标闭包
后来 JS 由于市场认同,战胜了 VBScript,Java plugin 等一系列加强浏览器的方案,成了事实标准。函数式编程
网景公司倒闭以后,JS 的标准制定由 ECMA(欧洲电脑制造商协会)制定,因此又叫作 ECMAScript, 新的标准叫作 ES六、ES七、ES2018 … 每一年会收集各类语言规范建议,经过 草案、stage一、stage2 等几个阶段,并在浏览器中有实现后会成为正式标准。函数
因此 JS 具备如下特色:this
会在项目里使用还在草案阶段的新语法
变种、超集、子集 不少(coffee script, typescript, Action Script, flow, AssembleScript)
JS 中的基本类型有如下几种:
另外有三种引用类型:
和 Java 同样,全部类型都是基于 Object(除了 undefined ?)
经过 「var」关键字声明一个变量,方法和大多数语言同样。
JS 是动态语言,变量不用区分类型,不一样类型之间的变量能够相互赋值。
var foo = 1; var bar; var a, b, c; bar = foo = “abcd” undefined 和 null
当一个值没有初始值的时候,默认值为 undefined。
undefined 在 JS 中是个语言设计的缺陷例子。
undefined 的行为在大多数状况下和 null 同样,都是不可访问的值,可是在 typeof 的时候结果不一样
var und; var nl = null; typeof und === ’undefined’ typeof nl == ‘object’
Boolean, Number,String 的行为和大多数语言同样。
能够直接声明也能够经过构造函数、工厂模式声明,三者没什么区别。
var a = 123 var a = new Number(123) var a = Number(123)
在 JS 中 数字的取值范围是 -253 - 1 到 253 - 1,范围小于 long 型,而且计算时有精度问题
1.2 / 0.2 // 5.999999999999999
声明数字的方式和其它语言相似,科学计数法、八进制、十六进制
var a = 1e3 // 1000 var a = 0o12 // 10 var a = 0xa // 10
经过 「toString」方法能够转换成字符串,并设置进制
var a = 1000 a.toString(10) // “1000” a.toString(8) // “1750” a.toString(16) // “3e8”
在 JS 中,有两个特殊的数字,NaN 和 Infinity。
当字符串或者其余类型转换成数字失败的时候,就会返回 NaN,可是 NaN 的类型依然是 number。
NaN 和任何数字计算后,结果都是 NaN。
当数字除以 0 的时候,就会返回 Infinity。
Number(undefined) // NaN Number(null) // 我也很费解,为何 null 转换成数字就是 0 // 0 Number("asdf") // NaN 10 / 0 //Infinity
在 JS 中字符串是可变长,并且能够经过 「+」 操做符作拼接。
字符串在内容中应该是双字节储存,能够经过索引访问每一个字符,而不是每一个 byte。
在浏览器中编码格式根据网页的编码格式而设置(在 node 中默认是 UTF8?)
在 JS 中,声明一个字符串经过单引号或者双引号均可以,两者没有区别。一般习惯是经过单引号访问,由于能够少按一个 shift。
var a = ‘123’ var b = “123” a == b a[0] // 经过索引访问的结果仍然是个字符串 // “1”
函数在 JS 中是一等公民,能够赋值给变量,有两种声明方式
function plus(a, b) { return a + b} var plus = function(a, b) { return a + b }
第二种方法实际上是将一个「匿名函数」复制给了变量 plus。
这两种方式在使用上没太大区别,除了在「声明前置」的场景下会有点区别
匿名函数还有一种方法叫作「当即执行函数」。
(function(a, b){ return a + b })(10, 20) // 30
函数只会将 return 声明的表达式的值返回出去,在函数没有声明 return 的时候,默认返回 undefined
function plus (a, b) { a + b } plus(1, 2) // undefined
函数和做用域
函数和变量同样,能够在任何地方声明、使用,
每一个函数独立出了一个做用域,做用域能够互相嵌套。
函数做为一个变量,自己也在父做用域下
function foo(b) { var a = 10 // 这里属于 foo 的做用域,内部有 bar, b, a 三个变量 function bar() { var c = 20; return a + b + c // 这里属于 bar 的做用域,由于在 foo 以内,因此能够访问 a 和 b } // 这里不能访问 c return bar(); }
因为 JS 在设计的时候,怕用户不理解变量须要先声明再使用,因此对变量会有「声明前置」,帮助你们提早声明所须要的变量。
下面咱们用当即执行函数建立一个闭包来解释什么叫「声明前置」
(function() { console.log(fn, foo); function fn(a, b){ return a + b }; var foo = 1234; console.log(fn, foo); })() // function (a, b){ return a + b } undefined // function (a, b){ return a + b } 1234
上面的代码至关于:
(function() { function fn(a, b){ return a + b }; var foo; console.log(fn, foo);• foo = 1234; console.log(fn, foo); })()
若是咱们用匿名函数赋值给一个变量,那么会有下面效果:
(function() { console.log(fn, foo); var fn = function(a, b){ return a + b }; var foo = 1234; console.log(fn, foo); })() // undefined undefined // function (a, b){ return a + b } 1234
上面的代码至关于:
(function() { var fn, foo; console.log(fn, foo); fn = function(a, b) { return a + b}; foo = 1234; console.log(fn, foo); })()
在 JS 中数组是可变的,并且数组内能够听任何值。
数组的长度是最后一个元素的索引加一。
若是访问没有设置的元素,将会返回 unfined
var array = []; array[0] = 1; array[2] = “1234”; array[4] = function(){}; // [1, undefined, “1234”, function(){}] array[1] // undefined
js 数组中自带了不少方法,方便咱们对数组作操做,好比说 map, reduce 等等
[1, 2, 3].map(function(d) { return d + 1 }) // [2, 3, 4] [1, 2, 3].reduce(function(r, d) { return r + d }, 0) // 6
若是想要删除数组中的某个元素的话,咱们能够用 delete 关键词,或者直接将索引的位置设置成 undefined
var array = [1, 2, 3] delete array[1] // [1, undefined, 3]
若是咱们须要删除数组中某个元素,而且缩短数组长度的话,就须要用到 splice。
var array = [1, 2, 3] array.splice(1, 1) console.log(array) // [1, 3]
一些经常使用的数组方法还有 slice, forEach, find, every, includes 等等
和 java 同样,对象(Object) 是全部类型的基类。它相似 JSON 里的键值对结构体,能够动态的挂载任何属性。
声明的方法有两种,{} 和 new
var a = {} var b = new Object() a.num = 1 a.str = "1234" console.log(a) // { num: 1, str: "1234"}
对象(Object)有点相似 Java 里的 HashMap,但 Key 只能是字符串。能够经过相似数组索引的方式来访问对象上的键。
这种方法和点操做符是同样的效果,当键名由一些特殊的字符组成的时候,咱们能够经过索引方式访问。
var obj = {value: 1234} console.log(obj["value"]) // 1234
这样声明或者访问会报错:
var obj = { some-value: 1234 } obj.some-value
咱们须要让编译器知道 some-value 是一个键名,因此须要将它们用引号括起来
var obj = { "some-value": 1234 } obj["some-value"]
当一个对象中挂载了一个函数,在函数中能够经过 this 来访问对象内的其余属性,this 也能够理解为「执行上下文」
function fn () { console.log(this.value) } var obj = { fn: fn, value: 1234 } obj.fn() // 此时 fn 的执行上下文就是 obj // 1234 var otherObj = { fn: fn, value: "abcd"} otherObj.fn() // 此时 fn 的执行上下文就是 otherObj // "abcd"
因为函数和数组是全部类型的基类,因此能够像对象同样随意的扩展属性。
可是字面量(如数字、布尔值、字符串、null、undefined) 是不能随意扩展的。
function plus(a, b) { return a + b} plus.value = 1234 plus(12, plus.value) // 1246 var array = [] array.value = 1234 console.log(array.value) // 1234 var a = true; a.value = 1234 console.log(a.value) // undefined
JS 的运算符和其余语言基本相似,就+-*%/这些,外加一些二进制操做符。
但由于 JS 弱类型的特性,有些场景是其余语言没有的,好比一个数字加一个字符串,结果是什么?
1+"2" // "12"
这种场景还能够理解,数字和字符串相加的时候,数字经过调用 toString 被转换成了字符串。
1 + {} // "1[object Object]"
数字和对象相加的时候,对象和数字都调用了 toString,被转换成了字符串
{} + [] // 0
可是空对象和空数组相加结果倒是 0,我也不知道为何
var obj = {} if (obj) console.log("obj is true") // "obj is true" obj == true // false
上面这个例子中,obj 是个空对象,在 if 条件判断中被看成真值,可是和 true 对比的时候却返回 false。
JS 的隐式转换规则很诡异,不少都是为了兼容早期版本中错误的实现,这里不必细究转换规则是什么。
咱们只须要记住之后用严格相等符(===)做对比,避免不一样类型的变量相互运算。
"1" == 1 // true "1" === 1 // false
JS 的循环和其它相似,也都是 for, do..while 这种写法。
可是,咱们通常不用 for 做循环,而是用数组方法 forEach,map(由于 for 写起来很麻烦,并且还须要单独声明一个变量)
[1, 2, 3].forEach(function(value) { return value + 1; }) // [2, 3, 4]
另外还能够经过 for...in 来遍历一个对象
var obj = {a:1, b:2, c: 3} for (var key in obj) { console.log(key) } // "a" // "b" // "c"
但咱们通常也不这么用,而是用 Object.keys 取得包含对象全部键的数组
var obj = {a:1, b:2, c: 3} Object.keys(obj) // ["a", "b", "c"] Object.keys(obj).forEach(console.log) // "a" // "b" // "c"
第一题:JS 的运用领域都有哪些,做为弱类型的语言执行效率如何,为何?
第二题:typeof 关键字的返回值有几种结果?
第三题:下面两种写法有什么区别
{ 0: "a", 1: "b", 2: "c" } ["a","b","c"]
第四题:下面代码的运行时会不会报错,this 指向哪里?
function fn () { console.log(this.value) } fn()
第五题:声明的变量是如何被回收的