在学JavaScript
主流浏览器
| 浏览器 | 内核 |
|---|---|
| IE | trident |
| chrome | webkit=>blink(webkit) |
| safari | webkit |
| firefox | gecko(壁虎) |
| opera | presto |
浏览器历史和JS诞生
- 1990
- 蒂姆 伯纳斯 李 超文本分享资讯的人
world wide web移植到C libwww/neus允许别人浏览他人编写的网站 - 1993
- 美国伊利诺大学NCSA阻止(马克 安德森)MOSIAC 浏览器显示图片 图形化浏览器
- 1994
- 马克 安德森和吉姆 吉拉克硅谷 SGI
- MOSIAC communication corporation
- 网景公司 netscape navigator ->2003
- 1996
- 微软收购spy glass
- IE internet exploror 1.0
- IE 3 的诞生出现了第一个脚本语言 Jscript
- 网景公司Brendan eich 在NETSCAPE
- NAVIGATOR 开发出了livescript
- 2008
- V8引擎
- 直接翻译机器码
- 独立于浏览器运行
- V8引擎
- 蒂姆 伯纳斯 李 超文本分享资讯的人
编程语言
- 编译型
- 翻译过程: 源码->编译器->机器语言->可执行文件
- 优点
- 运行速度快
- 缺点
- 跨平台需要重新编译
- 解释型
- 翻译过程:源码 -> 解释器 –> 解释一行执行一行
- 优点
- 不需要根据不同的平台重新编译
- 缺点
- 运行速度慢
脚本语言
动态语言 -> 脚本语言 -> 解释型语言 -> 弱类型语言
静态语言 -> 编译型语言 -> 弱类型语言
-
脚本语言-> 脚本引擎-> 解释器 前后端都有
JavaScript: 客户端脚本 JavaScript 解释器是在浏览器上的
php: 服务端脚本 php 解释器是在服务器上的
python 可以通过解释器编译成其他类型语言
- 如Jython,CPython
ECMA
European Computer Manufactures Association(欧洲计算机制造联合会) ECMA - 262 脚本语言的规范 ECMAScript ES5、ES6 规范化脚本语言
单线程=>模拟多线程
单线程 -> 一次只能做一件事
多线程-> 一次可以做多件事
- javascript 的引擎是单线程的
- 轮转时间片
- 短时间内轮流执行多个任务片段
- 任务1 任务2
- 切分任务1 任务2
- 随机排列这些任务片段,组成队列
- 按照这个队列顺序将任务片段送进js进程
- js线程执行一行一个又执行一个
耦合
高内聚,低耦合 模块的单一责任制
一个大块或者一个模块具有强的功能性,具有高的独立性
解耦合
JavaScript重点
- ECMAScript
- 语法,变量关键字,保留字,值,原始类型,引用类型
- DOM(document object model) 文档对象模型
- W3C 规范增删改查标签
- BOM (browser object model) 浏览器对象模型
- 没有相应的规范,可以写相容性
- 由于每个浏览器的厂商不一样,所以没有相应的规范
- 事件
- 没有相应的规范,可以写相容性
JS的值
- 原始值 -> 基本类型
- Number
- String
- Boolean
- undefined
- null
- 引用值
- object
- array
- function
- date
- RegExp
判断类型
typeof
console.log(typeof(a)) // 此时的a 没有定义则是 undefined
console.log(typeof(typeof(a)) // typeof 的返回值是 字符串
声明变量
括号运算> 普通运算> 赋值
函数
基本函数的写法
// 基本写法 函数声明
function text (参数){
// 执行语句
}
// 匿名函数表达式 函数字面量
var text = function text1 (){
// 执行语句
// 此时的text1 对外不可见
}
// 形参 -> 占位-> 形式上占位 -> 形式参数 -> 形参
function test(a,b){
// 如果没有传进这个参数则会报错
// 形参相当于在函数内部声明了 例如 var a
console.log( a + b )
}
// 实际参数 实参 => 按顺序 => 换位置无效
// 如果在函数调用实参中传入多余参数 与形参不相等 则 不报错 与形参数量一一对应多余的存入arguments 里
test(11,22)
function test(a,b){
b = 3
console.log( arguments[1] )
// 此时打印的为undefuned
// 如果是参没给传进来值 => b=undefined => undefined 无法给赋值
// 如果在实参中传入值 -> 可以在函数内部修改值 -> 如果没用在实参中传入值 -> 则在函数内部修改值是没法用的
}
test(1)
function test(a,b){
a = 3
console.log( arguments[0] )
// 此时的 a 与 arguments[0] 是不是一个东西
// 此时的 a 在栈内存中存储 arguments 在堆内存中存储
// arguments 与实参中的值是一一一对应关系 映射关系 如果实参中的值没用的话 那么与arguments 建立不上连接 他怎么修改时没有用的 反而 如果实参中有的话 在函数内部将会映射到 arguments 里面 则 a 修改 arguments[0] 也会变 因为时一一对应关系
}
test(1,2)
每个函数必须有return 如果不写return的话js引擎默认在函数末尾添加return
return 的用法
- 终止函数执行,想在哪终止
return写在哪 - 返回任意值
全局变量VS局部变量
- 在全局声明叫做全局变量
- 在函数内部声明叫局部变量
- 函数内可以使用全局变量 全局不可以调用函数内变量
函数式编程
- 一个固定的功能或者是程序被封装的过程,实现一个固定的功能或者程序,在这个封装体中
需要一个出口和一个入口
- 入口就是参数,出口就是返回值
函数初始化参数
初始化参数 默认值:undefined
// a = 1 为 es6 的语法
function test(a=1,b){
console.log(a,b)
// 此时打出来的 a 是 1 b 是 22
// 因为 arguments 跟形参是映射关系一一对应,如果 arguments 里面的值为 undefined 则会取实参中的值 那么反过来 如果实参中的值是undefined 则会取 arguments 里面的值
}
test(undefined,22)
预编译
- 检查通篇的语法错误
- 预编译过程
- 解释一行,执行一行
函数声明整体提升,变量只有声明提升,赋值不提升
暗示全局变量
imply global variable
// 如果一个变量直接赋值了 没有声明则会挂载到 全局对象window上
b = 22
console.log(window.b)
AO activation object
活跃对象,函数执行上下文
- 创建了一个AO对象,寻找函数里面的形参和变量声明
- 寻找实参中的参数值赋值给形参
- 寻找函数体内函数声明
- 执行
function fn (a){
var a = 1
function a (){}
}
fn(2)
AO = {
// a:undefined
// a:2
a : function a (){}
}
如果AO中没有这个值则会去GO里面找
GO global object
全局执行上下文
- 寻找变量声明
- 找函数声明
- 执行
GO ===window
var fn1 = 123
function fn1(){}
GO:{
// fn1 : undefined
fn1 : function fn1(){}
}
为什么要了解AO和GO
因为要知道作用域 作用域链相关产生的一切问题
AO=>function独立的仓库
对象
var o ={
name:'zs',
age:18,
like:function(){}
}
// 对象有属性和方法
function test (a,b){}
// 函数也是一种对象类型 引用类型 引用值
// test.name test.length test.prototype
// 对象 => 有些属性是我们无法访问的
// JS引擎内部固有的隐式属性
// [[scope]]
// 1. 函数创建时,生成的一个JS内部的隐士属性.
// 2. 函数存储作用域链的容器,作用域链 => 存储了
// AO/GO
// AO,函数执期上下文
// GO,全局执行器上下文
// 函数执行完成后,AO是要销毁的,也就是说每一执行函数的时候都是一个新的AO,老的AO在执行完函数后被销毁了,AO是一个即时存储的容器
作用域与作用域链
[[scope]] => [[scope.chain]]
- 每一个函数被定义的时候,系统生成了
[[scope]]属性[[scope]]保存该函数的作用域链,该作用域链的第0位存储当前环境下的全局执行器上下文GO,GO里储存全局下所有的对象- 也就是说每一个函数定义的时候,就已经包含了
GO全局执行期上下文
- 也就是说每一个函数定义的时候,就已经包含了
- 当函数被执行是的前一刻作用域顶端的第0位,储存函数生成的函数执行期上下文
AO,同时第一位存储的是GO,查找作用域链式从上到下依次查找- 也就是说当函数执行的的前一刻必然作用域中存在一个
AO和一个GO
- 也就是说当函数执行的的前一刻必然作用域中存在一个
- 当函数体内函数被定义时,是在上个函数环境下,所以函数体内的函数这时的作用域就是外层函数体被执行期的作用域链
- 当函数体内函数执行时(前一刻),生成函数b的
[[scope]],储存函数体内函数的作用域链,顶端第0位存储函数内函数的AO,外层函数的AO和全局的GO依次向下排列 - 当函数体内函数执行完毕后他的
AO会被销毁,作用域链回到定义时的状态
闭包
- 当内部函数被返回到外部并保存时,一定会产生闭包,闭包产生原来的作用域链不释放,过渡的闭包可能回导致内存泄漏,或加载过慢
立即执行函数
中文名立即执行函数=> 英文名 IIFE immediately-invoked function expression
自动执行,执行完成以后立即释放,立即执行函数 =>初始化函数
(function(){})();
(function(){}()); W3C 建议这样写
一定是表达式才能被执行符号执行 ()=>也叫函数执行符=>括号括起来的任何东西 不是表达式也会被堪称表达式
函数声明变成表达式的方法 + - ! || && 在函数前加了之后 会立刻变成函数表达式 并且去掉函数名称如:
+ function test (){ // 代码块 }()
逗号运算符
括号里的逗号运算符
var num = (1,2)
console.log(num)
=> 打印结果为 2
也就是说逗号运算符 返回的结果是最后一个
对象
-
对象字面量
var obj = {} // 对象字面量 obj.name = 'zs' // 对象直接量 -
系统自带的构造函数
var obj = new Object() // 通过系统自带的构造函数构造对象 === 对象字面量 obj.name = 'zs' // 对象直接量 -
自定义构造函数
function Car (){ this.color = 'red' } var car = new Car() // 通过 new 实例化函数 如果 new 这个 this 指向的就是实例化对象 也就是这个 car Car() // 没有 new 的情况下执行了这个函数那么他在AO中的this储存的是window-
当这个
Car被实例化的时候,相当于普通函数被执行了,那么必然产生AO,AO一产生系统看到你在构造对象了那么会立即保存一个this={}到AO里去,当你new的时候构造函数的代码块都已经跑完了,当然他的this指向的是car也就是说实例对象,所以通过car.color可以访问到this里的color,所以他必然在函数末尾隐士的加上了return this -
在构造函数末尾
return原始值 则无效,如果return引用值 那么 这个构造函数则是return出来的那个AO = { this:{} } function Car (){ // this = { // color = 'red' // } this.color = 'red' // return this } var car = new Car()
-
包装类
原始值 => 简单类型是没有属性和方法的
var num = 11;
num.len = 3;
console.log(num.len) => undefined
// 他在中间进行了 new Number(num).len = 3 然后发现 num 是原始值保存不了 所以 内部 delete 了 在打印出来就是 undefined 因为 num 的 len 被删除了
var str = '我爱你呀'
str.length
console.log(str.length)
// 那么为什么str 也是原始值它可以拥有length 属性呢 那是因为 他在调用的时候 默认调用了 New String(str).length => 这样他就是对象了 他就可以拥有属性跟方法啦