最下面有几点疑问,路过的朋友帮忙解答下
七、JavaScript 的语法
- 多行注释 ,被/* */包裹的任意区域,它不能嵌套使用
function (a /* int */, b /* str */) {}
- 表达式 将会产生一个值,它可以写在任何需要值的地方。
- 语句 表示了一种行为,如循环和if语句,一个程序基本上就是语句的序列。
凡是在JavaScript期望语句的地方都可以写表达式,这样的语句叫做表达式语句。反之则不然:不能在需要表达式的地方使用语句。
- 有两种像语句的表达式类型,它们的语法类型是 二义 的。
- 对象字面量(表达式)看上去像块(语句):
{
foo: bar(3, 5)
}
- 具名函数表达式看上去像是函数声明(语句):
function foo() {}
为了避免二义性,在解析过程中,JavaScirpt不能使用对象字面和函数表达式作为语句,即表达式语句不能以 花括号 和 function关键字 内容开头。
- eval 在语句的上下文中解析它的参数。如果希望 eval 返回一个对象,需要用小括号将对象字面两括起来。
eval('{ x: 123 }')
// output: 123
eval('({ x: 123 })')
//output: { x: 123 }
- 在调用 数字变量 的方法时,区分是浮点数的小数点还是调用方法的点运算符是非常重要的。因此不可以写类似 1.toString() 这样的代码,必须使用以下一种方式:
1..toString()
1 .toString() // space before dot
(1).toString()
1.0.toString()
- 可以在 JavaScript 文件或者 <script> 标签的第一行加入以下代码来启用严格模式:
'use strict'
...
也可以为每个函数启用严格模式:
function foo() {
'use strict'
...
}
启用严格模式需要注意的问题:
- 启用严格模式可能会破坏 现有的 代码
- 变量必须被声明
- 函数必须在作用域的顶部声明
- arguments对象拥有更少的属性
- 无方法的函数中 this 的值为 undefined
- 设置或者删除不可改变的属性(对属性的非法操作)会抛出异常
- 严格模式中, eval 更加简洁
- with 语句不能再被调用
- 没有八进制数字
八、值
-
静态与动态。
在编程语言的语义和类型体系环境中,静态一般是指 “编译时” 或 “非运行时”,动态指的是 “运行时”。 -
静态类型 与 动态类型
在静态类型语言中,变量、参数和对象成员(JavaScript 称他们为属性)都有编译器编译时能识别的类型。编译器可以通过这些信息执行类型检查和优化编译的代码。
即使在动态类型语言中,变量依然有一个动态的类型,是指在执行的某一时刻变量值的类型。
JavaScript 是动态类型语言;变量的类型在编译的时候是不确定的。 - 静态类型检查语言 会在编译期间进行检查,动态类型检查语言 会在执行期间进行检查。一种语言可以同时做静态类型检查和动态类型检查。
- 原始值 包括布尔值、数字、字符串、null 和 undefined。
- 其它值都是 对象,包括 简单对象、数组、正则表达式。
两者之间最主要的区别是类别内是如何互相比较的。每一个对象有唯一的标识符并且只严格和自身相等:
let obj1 = {}
let obj2 = {}
obj1 === obj2 // false
let obj3 = obj1
obj1 === obj3 // true
相反,所有原始值,只要编码值相同,则被认为相等
-
原始值具有以下特点:
a. 按值进行比较
b. 不可改变:其属性不能被改变、添加或移除let str = 'string' str.length = 3 str.length // output: 6 str.add = 'add' str.add // output: undefined
c. 固定类型的组合:你不能够自定义原始值
-
对象的特点:
a. 按引用进行比较// two different empty objects { } === { } // output: false
b. 默认可变
对象属性可以很自由地被改变、添加和移除
c. 用户可扩展
构造函数可以被看做是自定义类型的补充
-
JavaScript 有两个“空值”用来表示信息缺失,undefined 和 null
- undefined 表示“没有值”,不存在的元数据。
- null 表示“空值”,意思是“没有对象”。在用到对象的时候它表示空值。
例如,访问一个 JSON 节点时返回值的意义如下
- undefined 表示删除一个对象属性或者数组元素
- null 表示将属性或者元素设置为空
undefined 和 null 是仅有的在访问任何属性抛出异常时都会得到的值
function returnFoo(x) { return x.foo } returnFoo(true) // output: undefined returnFoo(0) // output: undefined returnFoo(null) // output: Cannot read property 'foo' of null returnFoo(undefined) // output: Cannot read property 'foo' of undefined
-
undefined 出现的场景
- 未初始化的变量
- 缺失的参数
- 访问一个不存在的属性
- 函数中没有显式地返回任何值
-
null 出现场景
- null 是原型链最顶端的元素
Ojbect.getPrototypeOf(Object.prototype) // output: null
- 当字符串中没有匹配到正则表达式的结果时,RegExp.prototype.exec() 会返回null
/x/.exec('aaa') // output: null
-
undefined 和 null 的历史
JavaScript 采用了 Java 中将变量分为原始值和对象的处理方式。同时也使用 Java 中表示“非对象”的值 null。遵循 C语言 的先例,null 在强制转换为数字时会变为0( Java 不会这样)Number(null) // output: 0 5 + null // output: 5
值得注意的是,JavaScript 的第一版没有异常处理。因此,在遇到未初始化的变量和缺失的参数等异常情况时需要通过一个值来表示。null 是一个很好的选择,但是 Brendan Eich 想要在这个时候避免两种情况。
这个值不应该具有指向性,因为它表达的不仅仅是一个对象
-
这个值的强制转换不应该为 0,因为这会使错误难以发现
因此,Eich 将 undefined 作为另外一个空值加进了 JavaScript。它会强制转换为 NaN:Number(undefined) //output: NaN 5 + undefined //output: NaN
-
布尔值、数字和字符串这三种原始值都有相应的构造函数:Boolean、Number、String。这些构造函数有两种用法:
-
作为构造函数,它们 创建的对象 / 实例(称为 包装对象 )和它们包装的原始值有很大的不同
typeof new String('str') //output: 'object' new String('str') === 'str' //output: false
-
作为函数,它们会将值转换为相应的原始值。这是推荐的转换方法
String(123) //output: '123' String(new String('str')) === 'str' // true
包装实例是对象,而在 JavaScript 中没有比较对象的方法,即使是通过宽松相等 ==。
var a = new String('str') var b = new String('str') a == b // false
-
-
原始值没有私有方法,但是它们会从各自的包装器中 借调 方法
'str'.charAt === String.prototype.charAt //output: true 'str'.trim ==== String.prototype.trim //output: true
宽松模式和严格模式会以不同的方式处理“借调”过程。
在宽松模式中,原始值会在运行过程中转换为包装器:String.prototype.method = function () { console.log(this) // String {"str"} console.log(typeof this) // object console.log(this instanceof String) // true } 'str'.method() // call the above method
在严格模式中,对包装器原型方法的调用是透明的:
String.prototype.method = function () { "use strict" console.log(this) // str console.log(typeof this) // string console.log(this instanceof String) // false } 'str'.method() // call the above method
-
转换为布尔值:Boolean()
Boolean(NaN) // false
-
转换为数字:Number()
Number(undefined) // NaN Number(null) // 0 Number(false) // 0 Number(true) // 1 Number('123') // 123
-
转换为字符串:String()
String(undefined) // 'undefined' String(null) // 'null' String(false) // 'false'
-
Object() 把对象会转换为它们自身,undefined 和 null 会转换成空对象,而原始值会转换为包装后的原始值。
var obj = { foo: 123 } Object(obj) === obj // true Object(null) // {} Object(undefined) // {} Object('abc') instanceof String // true Object(NaN) instanceof Number // true
九、运算符
连等赋值 x = y = 0,可以看这个案例。
-
复合赋值运算符,
var1 op= var2
,var1 = var1 op var2
,这两个表达式是等价的,其中op
是一种二元运算符。以下列出所有的复合赋值运算符:- 算数运算符:
+=
、-+
、×=
、/=
、%=
。 - 位运算符:
<<=
、>>=
、>>>=
、&=
、^=
、|=
。 - 字符拼接:
+=
。
- 算数运算符:
-
宽松相等 ( == ) 和不等 ( != ) 会先尝试将两个不同类型的值进行转换,再使用严格相等进行比较。
如果运算数是如下类型:
(1) undefined 和 null,则它们被认为是宽松相等的undefined == null // true
(2) 一个字符串和一个数字,则将字符串转换为数字,使用严格相等比较两个运算数。
(3) 一个布尔值和一个非布尔值,则将布尔值转换为一个数字,然后(再次)进行宽松比较。' ' == false // true '0' == false // true '1' == true // true '2' == true // false '2' == false // false
(4) 一个对象和一个数字或者字符串,则尝试转换此对象为一个原始值(ToPrimitive() —— 将值转换为原始值),然后(再次)进行宽松比较。
(5) 其它情况宽松比较的结果为 false。特殊数字NaN和本身不相等
NaN === NaN
// false
严格不等x !== y
等价于!(x === y)
疑问1:
第九章运算符下第三点,"宽松相等 ( == ) 和不等 ( != ) 会先尝试将两个不同类型的值进行转换,再使用严格相等进行比较。",譬如:
'1' == 1 // true
但是比较:0 == null
,我们知道Number(null)
等于0
,结果为什么却是false
,如果把null
强制转换为数字类型,0 == Number(null)
,结果为true
。