JS是编译型言语
编译发生在代码实行前几微秒,简朴来讲就是js在实行前要举行编译,编译历程发生在代码实行前几玄妙,以至更短。
编译的步骤
- 词法剖析
以var a = 2 为例,词法剖析会将其分红三个有意义的代码块即词法单位。 - 语法剖析
将词法单位组合天生代表了顺序语法的组织的树,即笼统语法书(AST)。 - 代码天生
将AST天生可实行的代码。行将AST转化成一组机械指令。
LHS RHS
假如查找的目标是对变量举行赋值,那末就会运用 LHS 查询;假如目标是猎取变量的值,就会运用 RHS 查询。
词法作用域
决定于你在写代码时的块级作用域
优化
依赖于词法的静态剖析
eval with 会竖立新的作用域
在词法剖析阶段,没法晓得eval with会对作用域做如何的修正,此时引擎不再对作用域举行任何优化
函数作用域
函数声明 函数表达式
辨别函数声明和表达式最简朴的要领是看 function 关键字出现在声明中的位
置(不仅仅是一行代码,而是全部声明中的位置)。假如 function 是声明中
的第一个词,那末就是一个函数声明,不然就是一个函数表达式。
let
- 隐式的天生块级作用域
- 不存在变量提拔
提拔
缘由
变量(包含函数在内)的一切声明都邑优先实行,只要声明自身会提拔,而赋值或其他运转逻辑会留在原位置
历程
这意味着不管作用域中的声明出现在什么地方,都将在代码自身被实行前起首举行处置惩罚。
可以将这个历程抽象地设想成一切的声明(变量和函数)都邑被“挪动”到各自作用域的
最顶端,这个历程被称为提拔。
声明自身会被提拔,而包含函数表达式的赋值在内的赋值操纵并不会提拔。
闭包
定义
当函数可以记着或接见地点的词法作用域,实时是被作用域外挪用,就产生了闭包
模块
- 当代模块机制
- 将来的模块机制
关于this
绑定时刻点
是在函数运转时绑定的,而非定义时。它的上下文取决于函数挪用时的种种前提,和在那里定义的没有关联,只取决于函数的挪用体式格局。
绑定历程
当函数被挪用时,会竖立一个实行上下文,在这个上下文里包含了函数在那里没挪用(挪用栈),挪用函数的要领,参数等。this作为实行上下文的一个属性,可以在函数实行的历程当中用到。
绑定范例
默许绑定
即绑定到全局,严厉形式下回绑定到undefined。function foo() { console.log( this.a ); } var a = 2; (function(){ "use strict"; foo(); // 2 })()
隐式绑定
即绑定到最顶层(或近来挪用对象)上function fun() { console.log(this.a) } var obj2 = { a: 3, fun: fun, } var obj1 = { a: 2, obj2: obj2, } obj1.obj2.fun() // 3
- 显式绑定
即用call或apply手动举行绑定 - bind要领完成
new绑定(组织函数)
- 不存在
实在在js中不存在组织函数,我们所说的组织函数实在就是一般的函数,它只是用new被“组织挪用”罢了。 new发生了什么?
- 竖立(或者说组织)一个全新的对象。
- 这个新对象会被实行[[原型]]衔接。
- 这个新对象会绑定到函数挪用的this。
- 假如函数没有返回其他对象,那末new表达式中的函数挪用会自动返回这个新对象。
- 不存在
- 箭头函数 =>
对象
内置对象
基本范例在须要的时刻(比方说猎取长度),会被引擎默许转成内置对象,从而举行要领的挪用。
基本范例并非继续自内置对象
var strPrimitive = "I am a string";
typeof strPrimitive; // "string"
strPrimitive instanceof String; // false
var strObject = new String( "I am a string" );
typeof strObject; // "object"
strObject instanceof String; // true
Object.prototype.toString.call( strObject ); // [object String]
null
typeof null === Object;
道理是如许的,差别的对象在底层都示意为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判
断为 object 范例,null 的二进制示意是全 0,天然前三位也是 0,所以实行 typeof 时会返回“object”
拷贝
- 浅拷贝
Object.assign({}, obj) - 深拷贝
JSON.stringify
属性描述符
getOwnPropertyDescriptor(myObj, 'a')
defineProperty
Object.defineProperty(myObj, 'a', {
value: 2,
writable: true,
configurable: true,
enumerable: true
})
Getter 、Setter
var obj = {
get a() {
return this._a_
},
set a(val) {
this._a_ = val * 5
}
}
obj.a = 10
console.log(obj.a) // 50
var obj2 = {}
Object.defineProperty(obj2, 'a', {
get: function() {
return this._a_
},
set: function(val) {
this._a_ = val * 2
}
})
obj2.a = 15
console.log(obj2.a) // 30
存在性
- in
‘a’ in obj1 会搜检obj及其原型链上是不是有’a’ - hasOwnProperty
不会搜检原型链,假如须要可以Object.prototype.hasOwnProperty.call(myObj, ‘a’)
原型(prototype)
constructor
返回实例对象O的组织函数(的援用)。任何一个prototype对象都有一个constructor属性,指向它的组织函数,每一个实例也有一个constructor属性,默许挪用prototype对象的constructor属性
比方
function Test() {
this.name = 'test'
}
var test = new Test()
console.log(test.constructor === Test) // true
类constructor
组织函数 constructor 是用于竖立和初始化类中竖立的一个对象的一种特别要领.
class Polygon {
constructor() {
this.name = "Polygon";
}
}
class Square extends Polygon {
constructor() {
super();
}
}
class Rectangle {}
Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
let newInstance = new Square();
console.log(newInstance.name); //Polygon
proto
实例对象__proto__指向天生改对象的组织函数的原型
比方
|function Test() {
this.name = 'test'
}
Test.prototype = {
color: 'red'
}
var test = new Test()
console.log(test.__proto__ === Test.prototype) // true
console.log(test.__proto__)
Object.create
var foo = {
something: function() {
console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo );
bar.something(); // Tell me something good...
Object.create(..) 会竖立一个新对象(bar)并把它关联到我们指定的对象(foo)
如许 我们就可以充分发挥 [[Prototype]]
机制的威力(托付)而且防止不必要的贫苦
(比方使 用 new 的组织函数挪用会天生 .prototype 和 .constructor 援用)。
继续
原型继续
瑕玷
实例的属性都邑指向同一个援用
完成
function Parent() {
this.names = [1, 2, 3]
}
function Child() {
}
Child.prototype = new Parent()
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
console.log(child1.names) // [1,2, 3,4]
console.log(child2.names) // [1,2, 3,4]
借用组织函数
完成
function Parent() {
this.names = [1, 2, 3]
this.getName = function () {
console.log(this.name)
}
}
function Child() {
Parent.call(this)
}
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
console.log(child1.names)
console.log(child2.names)
瑕玷
每一个子实例都邑实例化要领一次,内存爆炸
组合继续(最经常使用)
完成
function Parent() {
this.names = [1, 2, 3]
}
Parent.prototype.getName = function () {
console.log(this.names)
}
function Child() {
Parent.call(this)
}
Child.prototype = new Parent()
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
child1.getName()
child2.getName()
瑕玷
- 子类实例上有一份父类的属性,两者反复形成内存糟蹋
- 父类的组织函数被挪用了两次
寄生式组合继续
完成
function Parent() {
this.names = [1, 2, 3]
}
Parent.prototype.getName = function () {
console.log(this.names)
}
function Child() {
Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
var child1 = new Child()
var child2 = new Child()
child1.names.push(4)
child1.getName()
child2.getName()
长处
属性不会再原型链上反复
行动托付
js中的继续实在就是在对象间竖立关联关联,而行动托付就是竖立这类关联关联的纽带。
(“原型”)面向对象作风
function Foo(who) {
this.me = who;
}
Foo.prototype.identify = function () {
return "I am" + this.me;
};
function Bar(who) {
Foo.call(this,who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function () {
alert("Hello," + this.identify() + '.');
};
var b1 = new Bar("b1");
var b2 = new Bar("b2");
b1.speak();
b2.speak();
对象关联作风
Foo = {
init:function (who) {
this.me = who;
},
identify:function () {
return "I am" + this.name
}
};
Bar = Object.create(Foo);
Bar.speak = function () {
alert("hello," + this.identify() + '.');
};
var b3 = Object.create(Bar);
b3.init("b3");
var b4 = Object.create(Bar);
b4.init("b4");
b1.speak();
b2.speak();