前端开发【第4篇:JavaScript基础】

时间:2023-03-08 23:55:07
前端开发【第4篇:JavaScript基础】

JavaScript简述

上一篇文章已经聊过JavaScript的历史了这里不再复述了直接切入正题,JavaScript是一门解释型、动态类型、弱类型语言。

解释型语言和编译型语言就类似看一本书,编译型语言就是直接把整本书给你翻译成中文让你看,效率高。解释型就是给你找一个翻译翻译一句你读一句相对编译型效率就底一些

动态类型语言:就是一个变量本身的类型不是在定义的时候就指定类型了,而是在在运行的时候动态赋值这个变量是什么类型的语言

弱类型语言与之对比的就是强类型语言拿Python举例:

# 定义一个变量
test_value = 1
# 我们赋值的时候已经指定这个变量为int类型我们可以使用进行int类型的操作
print(test_value + 1)
# 但是如果我们使用它进行字符串操作就会报错
print(test_value + "str_value")
"""
TypeError: unsupported operand type(s) for +: 'int' and 'str'
"""

强类型语言,现在如果你想用test_value进行字符串操作只能把它转为str类型

在看一下弱类型的代码JavaScript

let testValue = 1;
// 现在我们定义一个testValue为int类型并进行int
console.log(testValue + 1);
// 但是现下面的操作
console.log(testValue + "Hello World");
// 现在我们做字符串的拼接而这时候不需要转换,弱类型有时显得很方便,有时却又极易出错

哦~这里定义变量的时候ECMAScript6以后定义变量var将推出历史舞台改为:let 和const了

JavaScript存在方式

看一下HTML和JS的加载顺序

1.浏览器加载和渲染html的顺序

  1. 浏览器加载和渲染html的顺序
  2. IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的。
  3. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完)
  4. 如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独连接进行下载。
  5. 并且在下载后进行解析,解析过程中,停止页面所有往下元素的下载。阻塞加载
  6. 样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染。
  7. JS、CSS中如有重定义,后定义函数将覆盖前定义函数

2. JS的加载

  1. 不能并行下载和解析(阻塞下载)
  2. 当引用了JS的时候,浏览器发送1个js request就会一直等待该request的返回。因为浏览器需要1个稳定的DOM树结构,而JS中很有可能有代码直接改变了DOM树结构,比如使用 document.write 或 appendChild,甚至是直接使用的location.href进行跳转,浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以 就会阻塞其他的下载和呈现.

3.如何加快HTML页面加载速度

  1. 页面减肥。页面的肥瘦是影响加载速度最重要的因素删除不必要的空格、注释。将inline的script和css移到外部文件,可以使用HTML Tidy来给HTML减肥,还可以使用一些压缩工具来给JavaScript减肥
  2. 减少文件数量。减少页面上引用的文件数量可以减少HTTP连接数。许多JavaScript、CSS文件可以合并最好合并,人家财帮子都把自己的JavaScript. functions和Prototype.js合并到一个base.js文件里去了
  3. 减少域名查询。DNS查询和解析域名也是消耗时间的,所以要减少对外部JavaScript、CSS、图片等资源的引用,不同域名的使用越少越好
  4. 缓存重用数据。使用缓存吧
  5. 优化页面元素加载顺序。首先加载页面最初显示的内容和与之相关的JavaScript和CSS,然后加载DHTML相关的东西,像什么不是最初显示相关的图片、flash、视频等很肥的资源就最后加载
  6. 减少inline JavaScript的数量。浏览器parser会假设inline JavaScript会改变页面结构,所以使用inline JavaScript开销较大,不要使用document.write()这种输出内容的方法,使用现代W3C DOM方法来为现代浏览器处理页面内容
  7. 使用现代CSS和合法的标签。使用现代CSS来减少标签和图像,例如使用现代CSS+文字完全可以替代一些只有文字的图片,使用合法的标签避免浏览器解析HTML时做“error correction”等操作,还可以被HTML Tidy来给HTML减肥
  8. Chunk your content。不要使用嵌套tables
  9. 指定图像和tables的大小。如果浏览器可以立即决定图像或tables的大小,那么它就可以马上显示页面而不要重新做一些布局安排的工作,这不仅加快了页面的显示,也预防了页面完成加载后布局的一些不当的改变。
  10. 根据用户浏览器明智的选择策略。IE、Firefox、Safari等等等等
  11. 页面结构的例子

4.HTML页面加载和解析流程

  1. 用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
  2. 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
  3. 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
  4. 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;
  5. 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
  6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
  7. 浏览器发现了一个包含一行Javascript代码的<script>标签,赶快运行它;
  8. Javascript脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。杯具啊,突然就少了这么一个元素,浏览器不得不重新渲染这部分代码;
  9. 终于等到了</html>的到来,浏览器泪流满面……
  10. 等等,还没完,用户点了一下界面中的“换肤”按钮,Javascript让浏览器换了一下<link>标签的CSS路径;
  11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。

5.Yahoo对网页设计性能的建议,个人感觉是说得非常好的。

英文版:http://developer.yahoo.com/performance/rules.html

中文翻译:http://www.cnblogs.com/smjack/archive/2009/02/24/1396895.html

原文链接:http://renyongjie668.blog.163.com/blog/static/1600531201097062789/

所以我们建议一般JavaScript代码放在Body最下面,且最好是通过外链式

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--CSS样式建议放在head,外部调用-->
<link type="text/css" rel="stylesheet" href="xiaomi_box/box_css.css">
</head>
<body> <!--HTML页面内容 --> <!-- 建议放在body最下面,外部调用-->
<script type="application/javascript" src="4-1.js"></script>
</body>
</html>

JavaScript数据类型

JavaScript数据类型分为两类:原始类型(primitive type)和对象类型(object type)

原始类型:

数字、字符串、布尔值、还有两个特殊的原始值(null[空值]和undefined[未定义])

对象类型:

1、普通对象(集合-可以理解为字典且无序)

对象是属性的集合每个属性都是由"名/值组成"  可以理解为Python中的字典擦~   这个值可以是原始类型的数字、字符串也可以是对象

2、全局对象

有一个特殊的对象Global object

3、数组对象(有序的集合可以理解为列表)

数组(array),有序的集合可以理解为Python中的列表

4、函数对象

首先JavaScript里面没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承。

重要的事情说三遍:JavaScript中没有类和实例的概念他是一个纯面向对象的语言,你可以理解为它的对象是靠一个对象来创建的

网景公司在发明与设计JavaScript的目标,其中很重要的两点:

1. 简易版的Java;

2. 简易,简易还是简易。

Brendan Eich设计JavaScript的时候引入了Java一个非常重要的概念:一切皆对象。既然JavaScript里面有了对象,那么设不设计继承就是困扰Brendan Eich的一个问题,如果真是要设计一个简易的语言其实可以不要继承机制,继承属于专业的程序员,但是JavaScript里那么多的对象,如果没有一种机制,他们之间将如何联系了,这必然会对编写程序的可靠性带来很大的问题,但是引入了继承又会使用JavaScript变成了完整的面向对象的语言,从而提高了它的门槛,让很多初学者望而却步,折中之下,Brendan Eich还是选择设计继承,但绝不是标准的继承(说道这里我想起了同样使用EMCAScript标准设计的语言ActionScript,它里面就有很完整的继承,做起来很惬意,我常想这是不是JavaScript以后的趋势,说不定哪天JavaScript会变的搄更完美写了?)。折中是指Brendan Eich不打算引入类(class),这样JavaScript至少看起来不像面向对象的语言了,那么初学者就不会望而却步了(这是欺骗啊,进来后倒腾死你,这就是所谓的关门打狗了,而且现在不还是引入了class吗,但是这个class实际还是调用了原型链)。

Brendan Eich思考之后,决定借鉴C++和java的new命令,将new命令引入了JavaScript,在传统的面向对象的语言里,new 用来构造实例对象,new 会调用构造函数,但是传统面向对象的语言new 后面的是类,内部机制是调用构造函数(constructor),而Brendan Eich简化了这个操作,在JavaScript里面,new 后面直接是构造函数,如是我们可以这么写一个Person类:

        function Person(name) {
this.name = name
}
let personOne = new Person("Brendan Eich");
console.log(personOne.name)

这样就创建了一个新的实例了。但是new有缺陷。用构造函数生成实例对象是无法无法共享属性和方法,例如下面代码:

        function Person(name) {
this.name = name;
this.nation = 'USA';
}
let person1 = new Person("Brendan Eich");
let preson2 = new Person("Shuai Ge"); person1.nation = "China"; console.log(person1.nation); // China
console.log(preson2.nation); // USA

每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。和JavaScript工厂模式的缺点一样,过多重复的对象会使得浏览器速度缓慢,造成资源的极大的浪费。

考虑到这一点,Brendan Eich决定为构造函数设置一个prototype属性,这个属性都是指向一个prototype对象。下面一句话很重要:所有实例对象需要共享的属性和方法,都放在这个Prototype对象(原型对象)里面;那些不需要共享的属性和方法,就放在构造函数里面

实例对象一旦创建,将自动引用prototype对象的属性和方法。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。如是我们可以改写下上面的程序:

        function Person(name) {
this.name = name;
}
// 我们不需要指定prototype对象当我们创建对象的时候默认会生成
Person.prototype = {nation: "USA"}; let person1 = new Person("Brendan Eich");
let person2 = new Person("Shuai Ge"); console.log(person1.nation);
console.log(person2.nation);

当我们这样写程序时候Person.prototype.nation = 'China'; 所有实例化的类的nation都会变成China。

由于所有的实例对象共享同一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。prototype只是提供了实现JavaScript继承的一个很方便的途径和手段。

5、日期、正则、错误 三种有用的对象

从字面上就可以看出日期是就代表日期的对象,正则表达式对象,还有就是定义了错误的对象

总结一下就是:数字、字符串、布尔值、null、undefined、对象(集合-字典)、数组(列表)、函数、日期、正则、错误这些对象类型,记住一切皆对象

 数字类型

1、JavaScript中的数字是不区分整数和浮点数的,它们默认都是采用浮点数展示

默认ES5是支持16进制的,但是不支持8进制,在ES6中明确了二进制采用[0b或0B],8机制采用[0o或0O]表示

2、数字的+、-、*、/、加减乘除

这些复杂的运算符都是通过Math对象属性定义的函数和常量实现的

3、二进制浮点数和四舍五入误差

首先要明确一点在计算机的世界里计算机只是别0,1,我们平时看到的任何 在计算机的理解力都是0,1,只是在我们看前做了一个转换,有了这个前提我们来看下

console.log(0.1 + 0.2 )
// 0.30000000000000004

what's FK ~ 什么鬼?JavaScript采用了IEEE-754表示法基本上现代编程语言都采用的是这个,你以为其他语言就会是对的吗?天真你试试~~

原因是:

那么0.1和0.2转换成二进制分别是,

(0.1) => 0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 101
(0.2) => 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 01
然后对上面的两个二进制数字做加法,得到的结果是, 0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 01
再把这个二进制转换成十进制,就是我们前面的结果0.30000000000000004了

有写语言没有这个问题说明本质上对其做了封装~

ES6中也没有对其进行封装只提供了一个误差值~~!

那我们应该如何解决这个问题呢?两种方法:

变大求值

我们把float值放大N倍后为正数在进行计算

let a = 0.1;
let b = 0.2;
let ret = (a * 10 + b * 10) / 10;
console.log(ret);

字符串求值

let a = 0.1;
let b = 0.2; let ret = (a + b).toFixed(1);
let newRet = parseFloat(ret);
console.log(newRet);

日期类型

JavaScript语言核心包括Date()构造函数,用来创建表示日期和时间对象。这些日期对想的方法为计算提供了简单的API

let beforDate = new Date(2011, 0, 1);  // 2011年1月1日
let laterDate = new Date(2011, 0, 1, 17, 10, 30); //同一天,当地时间5:10:30pm
let nowDate = new Date(); // 当前日期和时间 let elapsed = nowDate - laterDate; //日期减法: 计算时间检核的毫秒数 laterDate.getFullYear(); // ==> 2011 获取年份
laterDate.getMonth(); // ==> 0 获取从0计数的月份
laterDate.getDay(); // ==> 5 得到星期几,0代表星期日,5代表星期一
laterDate.getHours(); // ==> 17:5pm 当地时间
laterDate.getUTCHours(); // 使用UTC表示小时的时间,基于时区

还有很多方法可以查看文档

字符串

字符串和Python中的字符串差不多ES6中加强了Unicode表示法,只要将码点放入大括号,就能正确解读该字符。

"\u{20BB7}"
// "