1.执行上下文/作用域/闭包
2.this/call/apply/bind
- 不用call和apply方法模拟实现ES5的bind方法(讲得很通俗易懂)
3.原型/继承
typeof原理
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了。该提案会导致 typeof null === 'null'。 js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:
1:整数 110:布尔 100:字符串 010:浮点数 000:对象
但是,对于 undefined 和 null 来说,这两个值的信息存储是有点特殊的:
null:所有机器码均为0 undefined:用 −2^30 整数来表示
所以在用 typeof 来判断变量类型的时候,我们需要注意,最好是用 typeof 来判断基本数据类型(包括symbol),避免对 null 的判断。
instanceof原理
根据原型链判断。
// 定义构造函数
function C(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
以上代码,会先去查询o.__proto__和C.prototype是否相等,相等则返回true。
假如没有找到,会去__proto__.__protp__上查询,如此类推,直到和C.prototype相等或者等于null。
// 定义构造函数
function C(){}
var o = new C();
o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
以上代码返回true也是一样的道理,因为查询到最后的__proto__为Object
寄生组合式继承
结合借用构造函数传递参数和寄生模式实现继承
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型属性
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
// 将父类原型指向子类
inheritPrototype(SubType, SuperType);
// 新增子类原型属性
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);
instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance2.colors.push("3"); // ["red", "blue", "green", "3"]
这个例子的高效率体现在它只调用了一次 SuperType 构造函数,并且因此避免了在SubType.prototype 上创建不必要的、多余的属性。于此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和isPrototypeOf()
这是最成熟的方法,也是现在库实现的方法
4.Promise
参考文献: