RainZhai / rainzhai.github.com

宅鱼
http://rainzhai.github.io
Apache License 2.0
2 stars 0 forks source link

javascript重点特性(闭包,变量对象VO) #5

Open RainZhai opened 7 years ago

RainZhai commented 7 years ago

闭包

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

无非就是变量解析的过程。

首先看一段话: 每次定义一个函数,都会产生一个作用域链(scope chain)。当JavaScript寻找变量varible时(这个过程称为变量解析),总会优先在当前作用域链的第一个对象中查找属性varible ,如果找到,则直接使用这个属性;否则,继续查找下一个对象的是否存在这个属性;这个过程会持续直至找到这个属性或者最终未找到引发错误为止。

所以,JavaScript中的所谓的高大上的闭包其实很简单,根本上还是变量解析。而之所以可以实现,还是因为变量解析会在作用域链中依次寻找对应属性的导致的。

就是一种允许函数向关联的父级作用域寻址的访问特权。

Javascript作用链域

全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。 当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找, 直至全局函数,这种组织形式就是作用域链。

RainZhai commented 7 years ago

变量对象VO

先函数声明前置,然后在变量声明,JS解释器通过变量对象(Variable Object, VO)来获取。VO是一个抽象概念的“对象”,函数的VO分为两个阶段——变量初始化和代码执行。在变量初始化阶段,VO按照如下顺序填充: 1.函数参数(若未传入,初始化为undefined) 2.函数声明(发生命名冲突会覆盖) 3.变量声明(初始化为undefined, 发生命名冲突会忽略)

function test(a, b){
  var c = 10;
  function d(){}
  var e = function _e(){};
  (function x(){});
  b = 20;
}
test(10);
//变量初始化阶段
AO(test)={
  a: 10,
  b: undefined,
  c: undefined,
  d: <ref to func "d">
  e: undefined
}
//代码执行阶段逐一赋值
VO['c'] = 10;
VO['e'] = function _e(){}
VO['b'] = 20;
//结果
AO(test)={
  a: 10,
  b: 20,
  c: 10,
  d: <reference  to FunctionDeclaration "d">
  e: function _e(){}
}
RainZhai commented 7 years ago

JavaScript原型,原型链 每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时, 如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype, 于是就这样一直找下去,也就是我们平时所说的原型链的概念。

特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

RainZhai commented 7 years ago

JavaScript值的类型,内存结构 基本类型: undefined、null、boolean、number、string、objcet、function 栈:原始数据类型(Undefined,Null,Boolean,Number、String)es6的Symbol 堆:引用数据类型(对象Object、数组Array和函数Function)

两种类型的区别是:存储位置不同; 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储; 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体

null,undefined 的区别 null 表示一个对象是“没有值”的值,也就是值为“空”; undefined 表示一个变量声明了没有初始化(赋值);

undefined不是一个有效的JSON,而null是; undefined的类型(typeof)是undefined; null的类型(typeof)是object;

Javascript将未赋值的变量默认值设为undefined; Javascript从来不会将变量设为null。它是用来让程序员表明某个用var声明的变量是没有值的。

typeof undefined //"undefined" undefined :是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没有定义。当尝试读取时会返回 undefined; 例如变量被声明了,但没有赋值时,就等于undefined

typeof null //"object" null : 是一个对象(空对象, 没有任何属性和方法); 例如作为函数的参数,表示该函数的参数不是对象; 注意: 在验证null时,一定要使用 === ,因为 == 无法分别 null 和undefined null == undefined // true null === undefined // false

RainZhai commented 7 years ago

new操作符具体干了什么 1、创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。 2、属性和方法被加入到 this 引用的对象中。 3、新创建的对象由 this 所引用,并且最后隐式的返回 this 。

RainZhai commented 7 years ago

callee 与caller callee返回正在执行的函数本身的引用,它是arguments的一个属性 1 这个属性只有在函数执行时才有效 2 它有一个length属性,可以用来获得形参的个数,因此可以用来比较形参和实参个数是否一致,即比较arguments.length是否等于arguments.callee.length 3 它可以用来递归匿名函数。

var a = function() {   
alert(arguments.callee); 
} 

caller返回一个函数的引用,这个函数调用了当前的函数。 使用这个属性要注意: 1 这个属性只有当函数在执行时才有用 2 如果在JavaScript程序中,函数是由顶层调用的,则返回null

var a = function() {   
alert(a.caller);   
}   
var b = function() {   
a();   
}   
b();  
RainZhai commented 7 years ago

javascript神(qi)秘(pa)问题测试 http://javascript-puzzlers.herokuapp.com

RainZhai commented 7 years ago

连续赋值运算

连续赋值从右至左

//a.x不能被赋值
var a = {n:1}; 
a.x = a = {n:2};  
alert(a.x); // --> undefined  

//a.n不能被赋值
var a = {n:1};  
a.n = a = {n:2};  
alert(a.n); // --> 2

//a[0]不能被赋值,说明连续赋值中,若最左的变量为其右边某对象的属性,或数组记录,则不进行赋值运算
var a = [0,1];  
a[0] = a = [4,5,6]; 
alert(a[0]);// --> 4
RainZhai commented 7 years ago

JavaScript运算符的类型转换

//加运算从左至右会把字符串 **左边相邻的和右边所有的**的运算元转换为字符串
"1"+2//->"12"
"1"+2+3//->"123"
1+"2"//->"12"
1+1+"2"//->"22"

//乘除的规则和减一样,会把**运算符左右的运算元转换为数字**
"1"-"2"//->-1
"1"-"1"-"2"//->-2
1-"2"//->-1
"1"-2//->-1

//引擎检查valueOf() 返回值类型,然后调用toString() 转化为字符串
{}+{} //-> "[object Object][object Object]"
{}-{} //-> NaN(乘除结果一样)

//引擎检查valueOf() 返回值类型,然后调用toString() 转化为字符串
[1]+[2] //-> "12" 
[1]-[2] //-> -1 (乘除规则和减一样)

[1,2]+[2] //->"1,22"
[1,2]-[2]//->NaN