1 类型及检测方式
- JS内置类型:
- 数据类型检测
(1)typeof :对于原始类型来说,除了 null 都可以显示正确的类型,对于对象来说,除了函数都会显示 object
(2)instanceof:instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype
(3)constructor:console.log((2).constructor === Number); // true,这里有一个坑,如果我创建一个对象,更改它的原型,constructor就会变得不可靠了
(4)Object.prototype.toString.call():
2 作用域
-
作用域:
作用域是定义变量的区域,它有一套访问变量的规则,这套规则来管理浏览器引擎如何在当前作用域以及嵌套的作用域中根据变量(标识符)进行变量查找 -
作用域链: 作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,我们可以访问到外层环境的变量和 函数。
作用域可以理解为变量的可访问性,总共分为三种类型,分别为:
-
全局作用域: 全局变量是挂载在 window 对象下的变量,所以在网页中的任何位置你都可以使用并且访问到这个全局变量,定义很多全局变量的时候,会容易引起变量命名的冲突;
-
函数作用域: 只能在函数内部才能访问到它
-
块级作用域,ES6 中的 let、const 就可以产生该作用域(如何用var实现块级作用域: 立即执行函数)
3 闭包
定义: 闭包是一个可以访问其他函数内部变量的函数。
闭包有两个常用的用途:
- 在函数外部能够访问到函数内部的变量,使用这种方法来创建私有变量
- 使已经运行结束的函数上下文中的变量对象继续留在内存中,因为闭包函数保留了这个变量对象的引用
4. New的原理
new 关键词的主要作用就是执行一个构造函数、返回一个实例对象,内部执行过程:1. 创建一个新对象;
2. 对象连接到构造函数原型上,绑定this(this指向新对象);
3. 执行构造函数(为对象添加属性、方法);
4. 返回新对象
实现:
function create(fn, ...args) {
if(typeof fn !== 'function') {
throw 'fn must be a function';
}
// 1、用new Object() 的方式新建了一个对象obj
// var obj = new Object()
// 2、给该对象的__proto__赋值为fn.prototype,即设置原型链
// obj.__proto__ = fn.prototype
// 1、2步骤合并
// 创建一个空对象,且这个空对象继承构造函数的 prototype 属性
// 即实现 obj.__proto__ === constructor.prototype
var obj = Object.create(fn.prototype);
// 3、执行fn,并将obj作为内部this。使用 apply,改变构造函数 this 的指向到新建的对象,这样 obj 就可以访问到构造函数中的属性
var res = fn.apply(obj, args);
// 4、如果fn有返回值,则将其作为new操作返回内容,否则返回obj
return res instanceof Object ? res : obj;
};
5. 原型/原型链
原型:
在 js 中我们是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性值,这个属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。当我们使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。
原型链:
- 由原型对象组成,每个对象都有 proto 属性,指向了创建该对象的构造函数的原型,proto 将对象连接起来组成了原型链
- 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象Object.prototype,如还是没找到,则输出undefined;
原型特点:
JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变
6. 继承
以下详细讲解几种常见的继承方式:
1. 构造函数继承(借助call):
function Parent1(){
this.name = 'parent1';
}
function Child1(){
Parent1.call(this);
this.type = 'child1'
}
console.log(new Child1);
2. 借助原型链
function Parent2() {
this.name = 'parent2';
this.play = [1, 2, 3]
}
function Child2() {
this.type = 'child2';
}
Child2.prototype = new Parent2();
console.log(new Child2());
3. 将前两种组合
function Parent3 () {
this.name = 'parent3';
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = 'child3';
}
Child3.prototype = new Parent3();
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play);
4. 组合继承的优化1
function Parent4 () {
this.name = 'parent4';
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = 'child4';
}
Child4.prototype = Parent4.prototype;
Child4.prototype.constructor = Child4;