JavaScript语言本质上有许多复杂的概念,但是却用一种看起来十分简单的方式体现出来,比如回调函数。因此JavaScript开发者通常只是简单地使用这些特性,并不会关心语言内部的实现原理。由于JavaScript不必理解就可以使用,因此通常来说很难真正理解语言本身么这就是我们面临的挑战。
JavaScript大部分情况下编译发生在代码执行前的几微秒(甚至更短)的时间内。
变量的声明应该距离使用的地方越近越好,并最大限度地本地化。
理解作用域
var a = 2;
简单概括:为一个变量分配内存,将其命名为a,然后将值为2保存进这个变量
事实上编译器会进行如下处理:
1、遇到var a,编译器会询问作用域是否已经有一个该名称的变量存在于同一个作用域的集合中。如果是,编译器会忽略该声明;否则它会要求作用域在当前作用域的集合中声明一个新的变量,并命名为a。
2、接下来编译器会为引擎生成运行时所需的代码,这些代码被用来处理a = 2这个赋值操作。引擎运行时会首先询问作用域,在当前的作用域集合中是否存在一个叫作a的变量。如果是,引擎就会使用这个变量;如果否,引擎会继续查找该变量(向上级作用域查找)。如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎(前提是程序运行在非“严格模式”下)。
引擎查找方式
当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。
RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器本身,从而对其赋值。
异常类型
ReferenceError同作用域判别失败相关,而TypeError则代表作用域判别成功了,但是对结果的操作是非法或者不合理的。
with
with可以将一个或有多个属性的对象处理为一个完全隔离的词法作用域
变量提升
函数声明会被提升到普通变量之前,函数先提升变量再提升
后面的函数声明还是可以覆盖前面的
Object对象方法
- defineProperty 定义对象值、可写性、可枚举性、可配置性等
var myObject = {};
Object.defineProperty(myObject, "a", {
value: 2,
writable: true,
enumerable: true,
configurable: true
})
myObject.a; // 2
- hasOwnProperty 检查属性是否存在对象中,不会检查原型链
var myObject = { a: 2 };
// in操作符会检查原型链
("a" in myObject); // true
("b" in myObject); // false
myObject.hasOwnProperty("a"); // true
myObject.hasOwnProperty("b"); // false
- propertyIsEnumerable 检查给定得属性名是否直接存在与对象中并满足enumerable:true
myObject.propertyIsEnumerable("a");
- keys 和 getOwnPropertyNames 前者返回所有可枚举属性,后者返回所有属性
Object.keys(myObject); // ["a"]
Object.getOwnPropertyNames(myObject); // ["a", "b"]