聊聊JavaScript-初遇JavaScript

JavaScript 详解系列,主要是对自学JavaScript的一个总结和分享.以语言对比的形式更快速的入门JavaScript.有Java或C++基础,更加深入的了解JavaScript.(快速掌握一门语言)

JavaScript是什么(Hello JavaScript)

JavaScript 是一种脚本,一门编程语言.它可以实时的更新静态网页、交互、动画、视频等.JavaScript是Web技术最重要的核心技术.

Web技术的蛋糕有三层

  • HTML 是一种标记语言,用来结构化网页布局内容并赋予内容含义.定义段落、标题、数据表等.相当于Android中的layout.xml文件来定义布局内容
  • CSS 一种样式规则语言,主要用于HTML内容样式,这个Android中Style.xml 一样的形式
  • JavaScript 是一种脚本语言,用来动态更新内容,动态设置数据等

引自MDN

JavaScript的组成:

  • ECMAScript 提供语言的核心功能(变量、操作符、对象、函数等)
  • DOM(文档对象模型) 定义了JavaScript 操作HTML文档的接口(提供了访问HTML文档如body、form、div等接口和操作方法) 实现了对DOM的动态操作
  • BOM(浏览器对象模型) 定义了操作浏览器的接口(提供了某些访问功能如浏览器窗口大小、版本信息、浏览器历史等)

参考《JavaScript高级程序设计3》、MDN

怎样向页面添加JavaScript

script 标签的使用

  • script 写在head标签内部

type 默认值为text/javascript,可以不用进行设置; 包含在元素内部的JavaScript代码被从上至下依次解释.在解释器将 标签之间再包含额外的JavaScript代码,只会下载和执行外部脚本文件,而嵌入的代码会被忽略 ,例子如下:

<script src="example-1.js"></script>

src 也可以使用外部域的URL

<script src="https://www.somewhere.com/afile.js"></script>

script 的属性:async defer 延迟脚本

如果在文档的

为了避免这个问题,现代Web应用一般都全部JavaScript引用放在``````元素中页面内容的后面

```html
<body>
<!-- 这里放内容 -->

<script src="example-1.js"></script>
</body>

如上代码,这样在解析JavaScript代码之前,页面的内容将完全呈现在浏览器中.

script 标签也提供了延迟脚本的属性,分别是:async 和 defer

script 元素的defer和async属性,浏览器就会按照script元素在页面出现的先后顺序对它们依次进行解析.就是在第一个script元素包含对代码解析完成以后,第二个script包含对代码才会被解析,……

  • defer 延迟脚本

这个属性的用途表明脚本在执行时不会影响页面的构造.脚本会被延迟到整个页面都解析完毕后再运行

<script defer="defer" src="example-1.js"></script>

上述代码,脚本将延迟到浏览器遇到


- async 异步脚本

> async 只适用于外部脚本,并告诉浏览器立即下载文件.async标记的脚本并不保证按照它们的先后顺序执行

```html
<!-- 异步脚本 async ,同样只适用于外部文件 不一定按照顺序执行-->
<script async src="example-1.js"></script>

还需要注意,在html文档的最上方加入如下代码:

<!DOCTYPE html> <!-- HTML 5 定义文档模式为标准模式,如果不定义在混杂模式下会影响css的呈现和JavaScript的解释执行 -->
<!-- noscript ,浏览器不支持脚本或者浏览器支持脚本,但是脚本被禁用的情况下才会显示noscript的内容其他情况下不显示 -->
<noscript>
<p>本页面需要浏览器支持(启用) JavaScript脚本</p>
</noscript>

JavaScript 基本概念

变量

ECMAScript 变量是松散类型的,可以用来保存任何类型的数据.也就是说每个变量仅仅是一个用于保存值的占位符而已.

变量定义如下:

var message;//未经过初始化的变量,会保存一个特殊的值undefined

unction doSoming(){
"use strict"//启用严格模式 对于某些不安全的操作会抛出错误
var message = 'hi';

var message = true;
message = 10;//有效 但不推荐这要使用 这样相当于定义了一个全局变量
}

var操作符定义的变量是该变量作用域中的局部变量,这个变量在函数退出后就会被销毁.省去var操作符会变成全局变量,外部函数的任何地方都可以访问,需要注意的是在局部作用域中定义全局变量是很难维护的.给未经声明的变量赋值在严格模式下会导致ReferenceError错误

在严格模式下,不能定义名为eval或arguments的变量,否则会导致语法错误.

数据类型

ECMAScript中有6中简单的数据类型:Undfined、Null、Boolean、Number、String、Object(Object本质上是由一组无序的名值对组成的).ECMAScript 不支持创建自定义类型(Java和C++是支持创建自定义类型的).由于ECMAScript数据类型具有动态性,就没有在定义其他类型的必要了

  • boolean 类型
//boolean 类型
var message = "mes";
var messageBoolean = Boolean(message);//字符串不为空 返回true; 非0的数字值返回true;object 不为空 返回true
alert(messageBoolean);

//注意不要使用下面的方式
//字符串message会被自动转换成了对应的Boolean值,由于存在这种自动执行的Boolean转换,要确切的知道什么是变量
if(message){
alert("Value is true");
}
  • Number
//永远不要测试某个特定的浮点数值
console.log(0.1+0.2);//0.30000000000000004
if(0.1+0.2 == 0.3){
alert("You Got 0.3");
}

//数值范围
var result = Number.MAX_VALUE + Number.MAX_VALUE;
alert(result);//false 超出数值范围

//NaN
console.log("NaN == NaN:"+(NaN == NaN));//NaN 和任何数值都不相等 包括NaN本身

//isNaN 会帮我们确定这个参数是否“不是数值”;如果返回true 表示不能转换为数值
console.log(isNaN(NaN));//true
console.log(isNaN(10));//false
console.log(isNaN('10'));//false
console.log(isNaN("blue"));//true
console.log(isNaN(true));// 1 false

//数值转换 将非数值转换成数值
//Number()
var num1 = Number("hello");//NaN
var num2 = Number("");//0
var num3 = Number(000011);//9
var num4 = Number(true);//1
var num5 = Number("00011");//11

console.log("num1",num1,"num2",num2,"num3",num3,"num4",num4,"num5",num5);

//parseInt 转换规则
//parseInt 处理整数是更常用的函数 会看其是否符合数值模式
var p1 = parseInt("1234blue");//1234
var p2 = parseInt("");//NaN
var p3 = parseInt("0xA");//十六进制 10
var p4 = parseInt(22.5);//22
var p5 = parseInt("070",8);//ECMAScript 3 认为是八进制 56;ECMAScript 5认为是十进制 70;为此我们可以指定基数来保证正确的结果
var p6 = parseInt("70");//70

var p7 = parseInt("0xf");//15
var p8 = parseInt("f",16);//15 p7 和 p8 可以看成是相等的

console.log("p1",p1,"p2",p2,"p3",p3,"p4",p4,"p5",p5,"p6",p6,"p7",p8);

//parseFloat 和 parseInt类似;需要注意的parseFloat只解析 十进制,十六进制字符串会被转换成0,解析字符串中的第一个小数点是有效的
//第二个小数点是无效的
var pf1 = parseFloat("1234blue");//1234
var pf2 = parseFloat("0xA");//0
var pf3 = parseFloat("22.5");//22.5
var pf4 = parseFloat("22.34.5");//22.34
var pf5 = parseFloat("0908.5");//908.5

console.log(pf1,pf2,pf3,pf4,pf5);
  • String/Object
function doString(){
//js 中字符串可以使用“或者单引号‘表示;而Java中的字符串只能以双引号表示
//ECMAScript 中这两种形式没有区别,表示的字符串完全相同;注意以双引号开头必须以双引号结尾,以单引号开头必须以单引号结尾
var frist = "frist";
var last = 'last';
var text = 'This is the letter sigma \n This is the letter prim';
console.log(text);
//ECMAScript 中的字符串是不可变的,也就是说字符串一旦创建 它们的值就不能改变
//要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个新值的字符串填充该变量
var lang = "java";
lang = lang + "Script";
//首先创建一个容纳10个字符的新字符串,然后在这个字符串中填充“java" 和 “Script” 最后一步销毁原来的字符串
//“Java”和字符串“Script” 这也是在旧版浏览器拼接字符串很慢的原因 现在的浏览器已经解决了这个低效率的问题(如何解决??)

//转换字符串 toString 可以输出以二进制 八进制 十六进制的字符串值
var nume = "10";
console.log(nume.toString());
console.log(nume.toString(2));
console.log(nume.toString(8));
console.log(nume.toString(10));
console.log(nume.toString(16));

//object 类型 创建对象和Java中的类似 都是通过new 关键字创建的
var o = new Object();//可以省去原括号 但是不推荐
//关于 object 的属性和构造函数 会在后面中详细的讲解
}

关于递增和递减操作符和其他基本的操作符和Java/C++中的逻辑一样的 这里就不进行讲解了 非常基础的东西,主要讲解与Java和C++中不一样的东西

理解ECMAScript的基本语句

基本的if、for、while、do-while、in、switch这些基本的语句几乎在所有的语言中都是通用的,如果你有其他语言基础了解一下即可

function doStatement(){

//if 语句,javascript的if语句和Java中的if语句一样 if语句后可以跟一行代码或代码块不过业界推崇的是始终使用代码块
//注意Javascript 的if语句中的条件可以是任意表达式,而且表达式的求值不一定是布尔值,ECMAScript会自动调用Boolean()转换函数
//将这个表达式的结果转换为一个布尔值,这一点跟Java的有所不同,Java的if语句条件必须是布尔值.
var i = 10;
if(i > 25)
alert('Greater than 25.');//单行语句
else{
alert('Less than or equal to 25.'); //代码块中的语句
}

//do-while while for 语句和Java的语句并没有区别,举个例子
//do-while语句
var li = 0;
do{
i+=2;
}while(i<10);
//for语句
for (let i = 0; i < array.length; i++) {
const element = array[i];
}
//包括for无限循环也和Java的一模一样
for(;;){
//TODO
}
//只给出控制表达式实际上就是把for循环转换成了while循环
for(;li<20;){
li++;
}

//while 语句
while (li<20) {
li+=2;
}

alert(i);

//for-in 语句,而在Java中没有for-in语句但是在kotlin中有for-in语句,kotlin中的一些语法也借鉴了ECMAScript中的语法
//语法的简洁确实在编程中提高了效率,这也是我为什么喜欢上了JavaScript和Kotlin这两种语言
//下面我们看这个例子
for (const propName in window) {
document.write(propName);
}
//需要注意的是ECMAScript对象的属性没有顺序,所以遍历返回的先后次序可能会因浏览器而异
//还需要注意的是如果表达式的对象的变量值为null或undefined,for-in语句会抛出错误.
//ECMAScript5 更正了这一行为,不再抛出错误,而是不执行循环体,建议在使用for-in循环之前,先检测该对象的值不是null或undefined
for (const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
}
}
}

label语句这个语句貌似只有JavaScript和Kotlin中见到过,主要个循环语句配和使用

// doLabel();

function doLabel(){
//label 语句,在Java中同样没有这样的语句但是在kotlin 中有这样的语句,kotlin大量借鉴了JavaScript语法
//label :statement label语句可以在代码中添加标签,以便将来使用,看下面的一个例子:
//label 语句一般都要与for语句等循环语句配合使用

//break 和continue语句都可以与label语句联合使用,从而返回代码中特定的位置
//这种联合使用的情况多发生在循环嵌套的情况中
var num = 0;
start:for(var i=0;i<11;i++){
for(var j = 0;j<10;j++){
if(i==5 && j==5){
break start;//强制退出内部和外部循环
}
num++
}
}
alert(num);//55
}

JavaScript的函数

ECMAScript 中函数是通过function关键字声明的,对函数的命名没有什么要求,但是在严格模式下不能把函数/参数命名为eval或argumentsECMAScript中的函数在定义时不必指定是否返回值,任何函数在任何时候都可以通过return语句后跟要返回的值,在Java和kotlin、C++等语言中必须要指定返回值的类型的

function sayHi(name,message){
alert(name,message);
eval(name);
return 100+name;
}
//报错误:Uncaught SyntaxError: Unexpected eval or arguments in strict mode
function eval(arguments){
"use strict"//启用严格模式 对于某些不安全的操作会抛出错误,严格模式下JavaScript的执行结果会有很大的不同
alert(arguments);
}

函数中的参数:

ECMAScript 函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型.

也就是说,即便定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数,可以传递一个、三个甚至不传递参数

(PS:感觉ECMAScript的这种弱定义不是很理解,这种方法容易出现错误,不像Java中的强制定义一样)

ECMAScript 为什么会这么做呢?

ECMAScript中的参数在内部是用一个数组来表示的.函数接收到的始终都是这个数组,而不关心数组中包含哪些参数.

实际上函数体内可以通过arguments对象(这也是为什么在严格模式下arguments不能用作参数和函数名的原因)来访问这个参数数组,从而获取传递给函数的每一个参数.arguments对象与数组类似. 使用arguments获取参数

//看下面的一个例子

function sayHi(){
alert("1: "+arguments[0]+" 2:"+arguments[1]);
}
sayHi("JakePrim","HelloWorld");

ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的.ECMAScript 函数不存在函数重载这一重要特性(因为传递的参数没有个数和类型限制)另一个与参数相关的重要方面,arguments对象可以与命名参数一起使用arguments的值永远与对应命名参数的值保持同步,没有传递值的命名参数将自动被赋予undefined 值

function doAdd(num1,num2){
arguments[1] = 10;//相当于重写了第二个参数,如果只传递了一个参数那么num2 还是undefined,如果传递了两个参数 num
if(arguments.length == 1){
alert(num1+10);
}else if(arguments.length == 2){
alert(arguments[0]+num2);
}
}
doAdd();

ECMAScript 函数没有签名,因为其参数是有包含零或多个值的数组来表示的. 而没有函数签名 真正的重载是不可能做到的

function addSomeNumber(params) {
return params + 100;
}

function addSomeNumber(params) {
return params + 200;
}
// 函数addSomeNumber 被定义了两次,后定义的函数覆盖了先定义的函数,因此这个函数的返回结果就是300
var result = addSomeNumber(100);//300

console.log(result);

总结ECMAScript的基本要素:

ECMAScript 中的基本数据类型包括Undefined、Null、Boolean、Number、String

与其他语言不同,ECMAScript没有为整数和浮点值分别定义不同的数据类型,Number类型可用于表示所有数值

严格模式为这门语言容易出错的地方施加了限制

ECMAScript提供了很多与C及其他类C语言中相同的基本操作符,包括算术操作符、布尔操作符、关系操作符、相等操作符及赋值操作符

无须指定函数的返回值,因为任何ECMAScript函数都可以在任何时候返回任何值

实际上,未指定返回值的函数返回的是一个特殊的undefined值

ECMAScript中也没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式传递的

可以向ECMAScript函数传递任意数量的参数,并且通过arguments对象来访问这些参数

由于不存在函数签名的特性,ECMAScript函数不能重载

文章作者: JakePrim
文章链接: https://jakeprim.cn/2019/07/07/javascript-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 JakePrim技术研究院
打赏