原型和原型链
原型
概念
构造函数、原型、实例的关系:每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。
①所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
②所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
③所有引用类型的__proto__属性指向它构造函数的prototype
原型链
概念
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
默认原型
默认情况下,所有的引用类型都继承自Object,即Object.prototype 位于原型继承链的顶端。
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
}
let instance = new SubType();
console.log(instance.getSuperValue()); // true
此时如果调用instance.toString()方法,则实际上的调用的Object.prototype上的方法。
原型与继承关系
instanceof
使用instanceof操作符可以确定原型与实例之间的关系。
console.log(instance instanceof Object); // true
console.log(instance instanceof SuperType); // true
console.log(instance instanceof SubType); // true
isPrototypeof()
使用isPrototypeof()方法,只要原型链中包含此原型,就会返回true。
console.log(Object.prototype.isPrototypeOf(instance)); // true
console.log(SuperType.prototype.isPrototypeOf(instance)); // true
console.log(SubType.prototype.isPrototypeOf(instance)); // true
作用域和作用域链
作用域
作用域是指程序中定义变量的区域,它决定了当前执行代码对变量的访问权限。
作用域分为:全局作用域、函数作用域
由于作用域的限制,每段独立的执行代码块只能访问自己作用域和外层作用域中的变量,无法访问到内层作用域的变量。
词法作用域
JavaScript采用的是词法作用域,即函数的作用域在函数定义的时候就决定了。
与词法作用域相对的是动态作用域,函数的作用域是在函数调用的时候才决定。
var value = 1;
function foo() {
console.log(value);
}
function bar() {
var value = 2;
foo();
}
bar(); // 1
作用域链
当可执行代码内部访问变量时,会先查找本地作用域,如果找到目标变量即返回,否则会去父级作用域继续查找...一直找到全局作用域。我们把这种作用域的嵌套机制,称为 作用域链。
function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar(b * 3);
}
foo(2); // 2 4 12
一共有三层作用域嵌套:
- 全局作用域
- 函数foo作用域
- 函数bar作用域
其中,函数参数包含在函数作用域中。
块级作用域
if (true) {
var a = 1;
}
console.log(a); // 1
运行上面的例子可以知道JavaScript原生不支持块级作用域,
在es6中提出了let和const关键字,使用let和const可以创建块级的作用域。
let和const区别:let声明的变量可以改变,值和类型都可以改变;而const声明的常量不可以改变,这意味着const一旦声明,就必须立即初始化,不能以后再赋值。
闭包
什么是闭包
闭包就是指有权访问另一个函数作用域中的变量的函数
把函数执行,形成私有上下文,并且保存和保护私有变量的机制,称为“闭包”,它是一种机制。
简单来讲,闭包就是函数内部定义的函数,被返回了出去并在外部调用。
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 这就形成了一个闭包
闭包的作用
- 保护:划分一个独立的代码执行区域,在这个区域中有自己私有变量存储的空间,而用到的私有变量和其它区域中的变量不会有任何的冲突(防止全局变量污染)
- 保存:如果上下文不被销毁,那么存储的私有变量的值也不会被销毁,可以被其下级上下文中调取使用