上一篇文章已经聊过JavaScript的历史了这里再也不复述了直接切入正题,JavaScript是一门解释型、动态类型、弱类型语言。javascript
解释型语言和编译型语言就相似看一本书,编译型语言就是直接把整本书给你翻译成中文让你看,效率高。解释型就是给你找一个翻译翻译一句你读一句相对编译型效率就底一些css
动态类型语言:就是一个变量自己的类型不是在定义的时候就指定类型了,而是在在运行的时候动态赋值这个变量是什么类型的语言html
弱类型语言与之对比的就是强类型语言拿Python举例:java
# 定义一个变量 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类型python
在看一下弱类型的代码JavaScript程序员
let testValue = 1; // 如今咱们定义一个testValue为int类型并进行int console.log(testValue + 1); // 可是现下面的操做 console.log(testValue + "Hello World"); // 如今咱们作字符串的拼接而这时候不须要转换,弱类型有时显得很方便,有时却又极易出错
哦~这里定义变量的时候ECMAScript6之后定义变量var将推出历史舞台改成:let 和const了正则表达式
看一下HTML和JS的加载顺序编程
1.浏览器加载和渲染html的顺序数组
2. JS的加载浏览器
3.如何加快HTML页面加载速度
4.HTML页面加载和解析流程
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数据类型分为两类:原始类型(primitive type)和对象类型(object type)
原始类型:
数字、字符串、布尔值、还有两个特殊的原始值(null[空值]和undefined[未定义])
对象类型:
一、普通对象(集合-能够理解为字典且无序)
对象是属性的集合每一个属性都是由"名/值组成" 能够理解为Python中的字典擦~ 这个值能够是原始类型的数字、字符串也能够是对象
二、全局对象
有一个特殊的对象Global object
三、数组对象(有序的集合能够理解为列表)
数组(array),有序的集合能够理解为Python中的列表
四、函数对象
首先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继承的一个很方便的途径和手段。
五、日期、正则、错误 三种有用的对象
从字面上就能够看出日期是就表明日期的对象,正则表达式对象,还有就是定义了错误的对象
总结一下就是:数字、字符串、布尔值、null、undefined、对象(集合-字典)、数组(列表)、函数、日期、正则、错误这些对象类型,记住一切皆对象
数字类型
一、JavaScript中的数字是不区分整数和浮点数的,它们默认都是采用浮点数展现
默认ES5是支持16进制的,可是不支持8进制,在ES6中明确了二进制采用[0b或0B],8机制采用[0o或0O]表示
二、数字的+、-、*、/、加减乘除
这些复杂的运算符都是经过Math对象属性定义的函数和常量实现的
三、二进制浮点数和四舍五入偏差
首先要明确一点在计算机的世界里计算机只是别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}" // "𠮷" "\u{41}\u{42}\u{43}" // "ABC" let hello = 123; hell\u{6F} // 123 '\u{1F680}' === '\uD83D\uDE80' // true
JavaScript的字符串和Python中的字符串操做有不少类似之处也仅限于类似。
let s = 'hello world'; // 建议JavaScript字符串使用单引号由于在HTML中CSS样式类的应用是使用双引号的 s.charAt(0); // ==> 'h' 第一个字符 s.charAt(s.length-1); // ==> 'd' 最后一个字符 s.substring(1, 4); // ==> 获取第1~4个字符相似列表切片 s.slice(1, 4); // ==> 同上 s.slice(-3); // ==> 'rld' 最后三个字符 s.indexOf('l'); // ==> '2' 获取字符第一次出现的位置 s.split(','); // ==> 分割成数组 s.replace('h', 'H'); // ==> 'Hello World' 全文字符替换 s.toUpperCase(); // ==> 'HELLO WORLD' 转为为答谢
一样和Python中同样字符串是只读的若是想修改,只能新建一个新的
JavaScript能够理解为只读数组也能够用数组的部分功能好比s[0]下标~~
而且JavaScript自己支持正则匹配功能~
let text = 'testing: 1, 2, 3'; // 文本示例 let pattern = /\d+/g; // 匹配全部包含一个或多个数字的实例 pattern.test(text); // 首先pattern定义了一个匹配方法,而后匹配的字符是text而后返回结果 基本上全部语言的匹配都大同小异 text.search(pattern); // ==> 9 首次匹配成功的位置 text.match(pattern); // ==> ["1", "2", "3"] 全部匹配组成的数组 text.replace(pattern, "#"); // ==> 'testing: #, #, #' text.split(/\D+/); // ==> ["", "1", "2", "3"] 用非数字字符截取字符串
布尔值
True 或者False和Python中同样
null和undefind
null
JavaScript中的null它表示一个特殊值,经常使用来描述“空值”。null在javaScript中也是一个特殊的对象,它能够表示数字、字符串、对象是无值的
undefind
JavaScript还有第二个值来表示值的空缺,可是他表示更深层次的空值,表示变量未初始化或者未定义
undefind通常能够理解为出乎意料的的系统级别的空值,而null表示正常的意料中的空值,虽然它俩不一样可是大多状况下能够互换的,可是在定义变量或者传参的时候建议使用null
全局对象
在原始类型和对象类型中,对象类型有个很是重要的对象:全局对象 全局对象定义的属性是全局定义的符号,JavaScript能够直接调用
JavaScript解释器启动的时候(或者页面浏览器加载新页面的时候),它将建立一个新的全局对象,并给它一组定义的初始属性
客户端window对象额外定义了一些全局对象,而且在代码最顶级-不在任何函数的JavaScript能够经过this关键字引用let global = this;
包装对象
JavaScript对象是一种复合值:他是属性或已命名值的集合经过 “.”【点】来调用属性值,当属性值是一个函数的时候称其为“方法”
咱们来看下面一个例子:
let s = 'hello world';
s.substring(1,4)
在JavaScript中字符串不是一个对象那为何他又属性和方法呢?
本质是:字符串在调用属性的时候会将字符串的值经过调用new string(s)的方式转换为对象,一旦引用结束就个被建立的对象就被销毁(其实在实现上并不必定销毁这个临时对象,整个过程看起来是这个样子)个人天啊~~
包括数字、和布尔值都是同理~ Number()或Boolean
"==" 等于运算将原始值和包装对象视为相等,单“===”全等运算将它们视为不等
不可变原始值和可变的对象引用
JavaScript中原始值(字符串、数字、null、undefind、布尔值)与对象(包括数组和函数)有本质的区别,原始值不能够修改好比9这个数你怎么改为其余值这自己就说不通9就是9他不能修改
字符串就不太明显了,能够用Python的理解,一样不能够修改,字符串是一段连续的内存地址
对于对象来讲他们是可变的可修改的,而且即便两个对象的属性及其相同的值他们也是不相等的,各索引元素彻底相等的两个数组也不相同
let arrayA1 = [1, 2, 3, 4] let arrayB1 = [1, 2, 3, 4] arrayA1 == arrayB1 false
我擦这是什么鬼?这个咱们能够理解为咱们建立了两个对象在内存中,两个不一样的内存地址怎么能相等呢?我觉的JavaScript在这里更精准些
咱们一般将对象称为引用类型(reference type) 今后来和JavaScript的类型区分开,依照术语对象之都是引用,这个“引用能够理解为对内存地址的引用”
let arrayA = []; //定义一个空的数组对象 let arrayB = arrayA; // 把arrayA的值赋值为arrayB arrayA[0] = 1; //给arrayA里加一个元素由于A和B一样指向的是一块内存因此B也随之修改 arrayA === arrayB true
上面是铁则化简就是:只有两个值引用的内存地址相同才相等
因此若是引用同一个内存地址那么一个值修改的时候另外一个值将一样修改,有时候你只想复制一份能够经过循环来取
a = [1, 2, 3, 4, 5, 'hello'] b = [] for(let i = 0; i <a.length; i++){ b[i] = a[i]}
复制完也是不一样的由于两个是不一样的对象须要注意
类型转换
这个里面须要注意的是:
相等性:
null == undefind 是相等的
"0" == 0 在比较以前将字符串转换为数字
0 == false 比较以前将布尔值转换为数字
“0” == false 在比较前将布尔值和字符串转化为数字
显示类型转换
除了布尔值和undefind以外的任何值都具备toString()方法这个方法一般和string()方法返回结果一致
// 二进制转换 let n = 17 binary_string = n.toString(2) //转换为二进制 octal_string = "0" + n.toString(8) //转化为8进制 hex_string = "0x" + n.toString(16) //转化为16进制
对象转换为原始值
({x: 1, x2: 2}).toString() "[object Object]" [1, 2, 3].toString() "1,2,3" (function(x){f(x);}).toString() "function (x){f(x);}" /\d+/g.toString() "/\d+/g" new Date(2017,9,12).toString() "Thu Oct 12 2017 00:00:00 GMT+0800 (中国标准时间)"
这个结果颇有意思~~
JavaScript对象到字符串转化的过程以下:
一、首先判断是否有toString()方法若是他返回一个原始值将这个值转化为字符串返回
二、若是没有toString()方法或者返回的不是一个原始值则调用则掉用valueOf()方法,若是存在这个方法则调用它,若是返回的是原始值则转化为字符串
三、不然javaScript没法从toString()或valueOf()方法中得到一个原始值则抛出异常
在对象到数字的过程当中作了以下操做
一、若是对象存在valueOf()方法调用他若是返回一个原始值将这个原始值转换为数字(若是须要的话)而后返回数字
二、不然若是具备toString()方法,后者返回一个原始值JavaScript将它转换并返回
三、异常
对象转换为数字的细节解释了为何 空数组会被转化为数字0数组默认继承了valueOf()这个方法返回一个对象在调用toString()方法转换为空字符,空字符在转化为数字,JavaScript “+”和“==”若是一个是对象JavaScript会将方法转化为原始值而不是其余素数运算符的方法执行对象到数字的转换
日期的状况比较特殊它是JavaScript语言核心惟一的预先定义类型,他定义了有意义的到字符串和数字的转换经过valueOf或toString()返回原始值将被直接使用而不是强制转换为数字或字符串
let块级做用于
ES6 新增了let
命令,用来声明变量。它的用法相似于var
,可是所声明的变量,只在let
命令所在的代码块内有效。
{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
因此for循环很适合let
for (let i = 0; i < 10; i++) { // ... } console.log(i); // ReferenceError: i is not defined
上面代码中,计数器i
只在for
循环体内有效,在循环体外引用就会报错。
下面的代码若是使用var
,最后输出的是10
。
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
上面代码中,变量i
是var
命令声明的,在全局范围内都有效,因此全局只有一个变量i
。每一次循环,变量i
的值都会发生改变,而循环内被赋给数组a
的函数内部的console.log(i)
,里面的i
指向的就是全局的i
。也就是说,全部数组a
的成员里面的i
,指向的都是同一个i
,致使运行时输出的是最后一轮的i
的值,也就是10。
若是使用let
,声明的变量仅在块级做用域内有效,最后输出的是6。
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
不容许使用提早
在ES5咱们调用1个变量的时候若是他没有声明默认是undefind,如今不能够了没有声明的变量不容许使用
暂时性死区
只要块级做用域内存在let
命令,它所声明的变量就“绑定”(binding)这个区域,再也不受外部的影响。
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
这里也觉得typeof将不是一个安全操做由于它会触发异常了若是变量没有声明
不容许重复声明在相同做用于块内
function func(arg) { let arg; // 报错 } function func(arg) { { let arg; // 不报错 } }
为何要引入块级做用域?
ES5 只有全局做用域和函数做用域,没有块级做用域,这带来不少不合理的场景。
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
上面代码的原意是,if
代码块的外部使用外层的tmp
变量,内部使用内层的tmp
变量。可是,函数f
执行后,输出结果为undefined
,缘由在于变量提高,致使内层的tmp
变量覆盖了外层的tmp
变量。
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
const
声明一个只读的常量。一旦声明,常量的值就不能改变。
这意味着这个常量一旦声明就必须马上赋值之后不容许修改
ES6中有了块级做用域,JavaScript的做用域链基本上和Python的做用域类似了 全局和局部做用域
特殊的是块级做用于的暂时性死区
直接定义原始类型也就是直接声明
let a = 1; let b = "hello" let c = null let d; // undefind
对象和数组的初始化表达式也就是直接声明对象和数组
let a = {}
let b =[]
函数定义表达式也就是声明一个函数
let function a { console.log("Hello World~ ")}
属性的访问
普通对象{} 能够经过.或者对象[‘key’]来进行访问,数组对象的话能够相似python的列表访问方式
若是属性对应的值是一个方法的话能够加()执行
对象建立表达式
let a = new Object()
加、减、乘、除、位运算
“==”和“===”相等和不等运算
== 和 === 、 == 为宽松的判断是否相等, === 为严格的判断是否相等, === 在判断的时候不会作类型的转换!!!
他是如何严格判断的呢?
不严格的==是如何判断的?
一、若是两个操做数类型相等,那么就相似严格相等
2.、若是操做两个数类型不一样可能相等:
比较运算符相似==可能会进行类型转换
instancefo相似Python中的isinstance
let nowDate = new Date() undefined nowDate instanceof Date true
Python的是
print(isinstance(11, int))
条件运算符JavaScript惟一一个三元运算符 ?
表达式: bool ? true: false 解释:问号前面为判断式,若是为真用 冒号前的true对应的表达式值计算而后返回,不然用冒号后面的false表达式计算并返回
// username须要提早定义ES6已经不容许未定义使用了 greeting = "hello" + ( username ? username : "there") // 等价于 let greeting = "hello"; if (username){ console.log(greeting + username); }else{ console.log(greeting + "there"); }
其余运算符
一、typeof获取类型
二、delete删除属性和python中的相似
三、逗号运算符哈哈
逗号运算符是二元运算符,它的操做数能够是任意类型。它首先计算左操做数,而后计算右操做数,最后返回右操做数的值,看下面的代码
i = 0, j = 1, k = 2 // 最后返回的结果是 2,它和线面的代码基本上是等价的 i = 0; j = 1; k =2
用在哪里?
// for循环中的第一个逗号是第let语句的一部分 // 第二个逗号是逗号运算符 // 它将两个表达式(i++和j--)放在一条for循环中 for(let i = 0, j = 10; i <j ; i++, j--){ console.log(i + j) }