JavaScript笔记(三)——语言基础

读书笔记

《JavaScript高级程序设计(第4版)》

语言基础

JavaScript是通过<script>元素插入到HTML页面中的。

  1. 要包含外部JavaScript文件,必须将src属性设置为要包含文件的URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
  2. 所有<script>元素会依照它们在网页中出现的次序被解释。在不使用defer和async属性的情况下,包含在<script>元素中的代码必须严格按次序解释。
  3. 对不推迟执行的脚本,浏览器必须解释完位于<script>元素的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。
  4. 可以使用defer属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。
  5. 可以使用async属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。
  6. 通过使用<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。

内容概要

3.1 语法

3.1.1 区分大小写

ECMAScript中一切都区分大小写。

3.1.2 标识符

标识符:变量、函数、属性或函数参数的名称。

  1. 第一个字符必须是一个字母、下划线(_)或美元符号($);
  2. 剩下的其他字符可以是字母、下划线、美元符号或数字。

注意:关键字、保留字、true、false和null不能作为标识符。

3.1.3 注释

ECMAScript采用C语言风格的注释,包括单行注释和块注释。

  1. // :单行注释
  2. /* 注释 */ :多行注释

3.1.4 严格模式

严格模式(strict mode)是一种不同的JavaScript解析和执行模型,ECMAScript3的一些不规范写法在这种模式下会被处理,对于不安全的活动将抛出错误。
要对整个脚本启用严格模式,在脚本开头加上这一行:

"use strict";

这是一个预处理指令。任何支持的JavaScript引擎看到它都会切换到严格模式。
也可以单独指定一个函数在严格模式下执行,只要把这个预处理指令放到函数体开头即可:

function doSomething() {
   
	"use strict";
	//函数体
}

3.1.5 语句

ECMAScript中的语句以分号结尾。

3.1.6 关键字与保留字

保留的关键字不能用作标识符或属性名。

3.3 变量

ECMAScript变量是松散类型的,意思是变量可以用于保存任何类型的数据。每个变量只不过是一个用于保存任意值的命名占位符。
var在ECMAScript的所有版本中都可以使用,
constlet只能在ECMAScript6及更晚的版本中使用。

3.3.1 var关键字

  1. var声明作用域
    使用var操作符定义的变量会成为包含它的函数的局部变量。
    如果需要定义多个变量,可以在一条语句中用逗号分隔每个变量(及可选的初始化):
var message = "hi",
	found = false,
	age = 29;
因为ECMAScript是松散类型的,所以使用不同数据类型初始化的变量可以用一条语句来声明。插入换行和空格缩进并不是必需的,但这样有利于阅读理解。

> 在严格模式下,不能定义名为eval和arguments的变量,否则会导致语法错误。
  1. var声明提升
    使用var时,使用这个关键字声明的变量会自动提升(hoist)到函数作用域顶部。
function foo(){
   
	console.log(age);
	var age = 26;
}
foo(); //undefined

之所以不会报错,是因为ECMAScript运行时把它看成等价于如下代码:

function foo(){
   
	var age;
	console.log(age);
	age = 26;
}
foo(); //undefined

此外,反复多次使用var声明同一个变量也没有问题:

function foo() {
   
	var age = 16;
	var age = 26;
	var age = 36;
	console.log(age);
}
foo(); //36

3.3.2 let声明

let和var的作用差不多,但有着非常重要的区别。
let声明的范围是块作用域,而var声明的范围是函数作用域。

if(true) {
   
	var name = 'Matt';
	console.log(name); //Matt
}
console.log(name); //Matt

if(true) {
   
	let age = 26;
	console.log(age); //26
}
console.log(age); //ReferenceError: age没有定义

let也不允许同一个块作用域中出现冗余声明。这样会导致报错:

var name;
var name;

let age;
let age; //SyntaxError:标识符age已经声明过了
  1. 暂时性死区
    let声明的变量不会在作用域中被提升。在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

  2. 全局声明
    与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)。

    var name = 'Matt';
    console.log(window.name); //'Matt'
    
    let age = 26;
    console.log(window.age); //undefined
    

    加粗样式let声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免SyntaxError,必须确保页面不会重复声明同一个变量。

  3. 条件声明
    由于var声明会被提升,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明。因为let的作用域是块,所以不可能检查前面是否已经使用let声明过同名变量,同时也就不可能在没有声明的情况下声明它。

    <script>
    	var name = 'Nicholas';
    	let age = 26;
    </script>
    
    <script>
    	var name = 'Matt'; //不需要检查之前是否声明过同名变量
    	let age = 36; //如果age之前声明过,这里会报错
    </script>
    
  4. for循环中的let声明
    在let出现之前,for循环定义的迭代变量会渗透到循环体外部:

    for(var i=0;i<5;++i){
         
    	//循环逻辑
    }
    console.log(i); //5
    

    改成使用let之后,这个问题就消失了, 因为迭代变量的作用域仅限于for循环块内部:

    for(let i=0;i<5;++i){
         
    	//循环逻辑
    }
    console.log(i); //ReferenceError:i没有定义
    

    在使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。

3.3.3 const声明

const的行为与let基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误。

const age = 36;
age = 36; //TypeError:给常量赋值

//const也不允许重复声明
const name = 'Matt';
const name = 'Nicholas'; //SyntaxError

//const声明的作用域也是块
const name = 'Matt';
if(true){
   
	const name = 'Nicholas';
}
const.log(name); //Matt

const声明的限制只适用于它指向的变量的引用。换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。

const person = {
   };
person.name = 'Matt'; //ok

JavaScript引擎会为for循环中的let声明分别创建独立的变量实例,虽然const变量跟let变量很相似,但是不能用const来声明迭代变量(因为迭代变量会自增):

for(const i=0;i<10;++i){
   } //TypeError:给常量赋值

可以用const声明一个不会被修改的for循环变量,也就是说,每次迭代只是创建一个新变量。这对for-of和for-in循环特别有意义:

let i = 0;
for(const j = 7; i < 5; ++i){
   
	console.log(j);
}
// 7,7,7,7,7

for(const key in {
   a: 1, b: 2}){
   
	console.log(key);
}
//a,b

for(const value of [1,2,3,4,5]){
   
	console.log(value);
}
//1,2,3,4,5

3.3.4声明风格及最佳实践

  1. 不使用var
    只使用let和const有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。
  2. const优先,let次之
    使用const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。只在提前知道未来会有修改时,再使用let。

3.4 数据类型

ECMAScript有6种简单数据类型(原始类型):Undefined、Null、Boolean、Number、String和Symbol。1种复杂数据类型:Object(对象)。Object是一种无序名值对的集合。

3.4.1 typeof操作符

确定任意变量的数据类型。对一个值使用typeof操作符会返回下列字符串之一:

  • “undefined”:值未定义
  • “boolean”:值为布尔值
  • “string”:值为字符串
  • “number”:值为数值
  • “object”:值为对象(而不是函数)或null
  • “function”:值为函数
  • “symbol”:值为符号

特殊值null被认为是一个对空对象的引用。

let message = "some string";
console.log(typeof messsage); //"string"
console.log(typeof(message)); //"string"
console.log(typeof 95); //"number"

注意:严格来讲,函数在ECMAScript中被认为是对象,并不代表一种数据类型。函数也有自己特殊的属性,通过typeof操作符来区分函数和其他对象。

3.4.2 Undefined类型

Undefined类型只有一个值,就是特殊值undefined。当使用var或let声明了变量但没有初始化时,就相当于给变量赋予了undefined值:

let message;
console.log(message == undefined); //true

在默认情况下,任何未经初始化的变量都会取得undefined值。

3.4.3 Null类型

Null类型同样只有一个值,即特殊值null。逻辑上讲,null值表示一个空对象指针,这也是给typeof传一个null会返回"object"的原因:

let car = null;
console.log(typeof car); //"object"

在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值。

if(car != null){
   
	//car是一个对象的引用
}

undefined值是由null值派生而来的,因此ECMA-262将它们定义为表面上相等。

console.log(null == undefined); //true

永远不必显式地将变量值设置为 undefined。但 null 不是这样的。任何时候,只要变量要保存对象,而当时又没有那个对象可保存,就要用 null 来填充该变量。这样就可以保持 null 是空对象指针的语义,并进一步将其与 undefined 区分开来。
null 是一个假值。也有很多其他可能的值同样是假值。所以一定要明确自己想检测的就是 null 这个字面值,而不仅仅是假值。

let message = null; 
let age; 
if (message) {
    
 // 这个块不会执行
} 
if (!message) {
    
 // 这个块会执行
}
if (age) {
    
 // 这个块不会执行
} 
if (!age) {
    
 // 这个块会执行
}

3.4.4 Boolean 类型

布尔值字面量 true 和 false 是区分大小写的
要将一个其
他类型的值转换为布尔值,可以调用特定的 Boolean()转型函数:

let message = "Hello world!"; 
let messageAsBoolean = Boolean<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值