JavaScript高级
一、原型
prototype属性
- 函数都有一个prototype属性,默认是一个Object空对象
- 函数对象中都有一个constructor,它指向函数对象
- 给函数原型对象添加方法,其实例对象可以调用
fun.prototype.constructor === fun //true
ps:
空对象:没有自身的属性
function fun(params) {
}
console.log(fun.prototype)
二、函数高级
a.原型与原型链
原型上的方法是给其实例对象使用的
每个函数function上都有一个prototype,即显示原型属性
每个函数function上都有一个__proto__,即隐示原型属性
对象的隐式原型的属性值是其构造函数的显性原型的值
function Fun(){ // 内部:this.prototype = {}
}
var fn = new Fun() //内部 this.__protp__ = Fn.prototype
console.log()
console.log(Fun.prototype === fn.__proto__) // true 地址值 都是指向原型对象
函数prototype是函数定义时自动添加的,默认空对象;对象__proto__是创建对象的时候自动添加的,默认指向构造函数的prototype属性值
原型链
Person构造函数和fun都未曾定义过toString,为什么不像fun.test()一样报错呢?
1.函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
Person.prototype instanceof Object //true
Object.prototype instanceof Object //false
2.所有函数都是Function的实例对象(包括Function)
3.Obect的原型对象是原型链的尽头(null)
function An() {
}
An.prototype.a = 'test'
var an1 = new An();
an1.a = 'test1'
var an2 = new An();
console.log(an1.a,an2.a) // test1 test
读取对象的属性值,会先在自身上找,再通过原型链找
设置对象的属性值,不会查找原型链,如果当前对象没有属性,会直接追加,再设置值
b.执行上下文与执行上下文栈
.执行上下文
1.全局执行上下文
- 全局将window为执行上下文
- 对全局数据进行处理
- 声明提前,变量注意 var let const ,函数注意 var n = fun(){} 与 function xx()
- 变量与函数同名,var 声明并复制,权重最大
- this 指向 window
- 执行
2.函数执行上下文 - 在调用函数,准备执行函数前,创建对应的函数执行上下文
- 对局部数据进行预处理
- 形参变量,赋值(实参),添加为执行上下文的属性
- argument(类数组),赋值(实参列表),添加为执行上下文的属性
- var 定义的局部变量,为undefined,添加为执行上下文的属性
- function声明的函数,赋值,添加执行上下文的方法
- this 赋值(调用函数的对象)
- 开始执行函数体
执行上下文栈
在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象;
在全局执行上下文(window)确定后,将其添加到栈中(压栈)
在函数执行上下文创建后,将其添加到栈中(压栈)
在当前函数执行完后,将栈顶的对象移除(出栈)
在所有的代码执行完,栈中只有window
ps:
栈:后进先出
队列:先进先出
c.作用域(scope)与作用域链
全局作用域
函数作用域在函数定义的时候就确定了,而不是说调用的时候
局部作用域
块级作用域
注意var 变量的位置
作用域是静态的,而上下文是动态的,比如函数调用或结束时改变
作用域是由内向外,依此查找,注意声明的地方
d.闭包
闭包:嵌套的内部函数,包含这被引用变量(函数)的对象。闭包存在于嵌套的内部函数。
看变量a与变量b区别,a内部调用,就产生闭包,b就不产生
闭包产生:
1.函数嵌套
2.内部函数调用局部调用
3.内部函数定义执行完
闭包的作用
1,使用函数内部的变量在函数执行完,仍然存活在内存中,延长局部变量的生命周期
2.让函数外部可以操作(读写)到函数内部的数据
闭包的缺点
优点有时候也是缺点,清除赋值null
a.内存溢出
b.内存泄漏
三、线程机制与事件机制
线程
- 进程:进程是指程序的一次执行,它占有一片独有的内存空间,
- 线程:线程是指CPU的基本调度单位,是程序执行的一个完整流程,是进程内的一个独立执行单元。多线程是指在一个进程内, 同时有多个线程运行。
js 单线程
-
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
-
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假如JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
-
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
-
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
-
这里所谓的单线程指的是主线程是单线程的,所以在 Node 中主线程依旧是单线程的。
-
因为是单线程,所以所有任务都需要排队,前一个任务结束,后一个任务才能执行,如果前一个任务花费时间较长,后一个任务等待时间也随之变长。
-
js可以做到先把等待中的任务先放一边晾着,去处理后面的任务
-
于是所有任务可以分为两种,一种是同步任务,另一种是异步任务:同步任务很简单,前面的任务完成后面才能执行,一个接一个地执行任务。异步任务不占用主线程,直接进入“任务队列”中,等任务队列通知主线程,某个任务可以执行了,才会进入主线程执行。
异步执行机制
- 所有同步任务都在主线程上执行,形成一个执行栈。
- 主线程之外,还存在一个“任务队列”。只要异步任务有了运行结果,就在“任务队列”中放置一个事件。
- 一旦执行栈中的所有同步任务都执行完毕,就会去“任务队列”中读取新的任务放到执行栈中,再依次执行任务。
- 只要主线程空了,就会读取任务队列,这就是js的运行机制。这个过程会不断地重复。
上一篇: OpenSolaris 2008.11 final 发布了
下一篇: tomcat 设置允许跨域访问