__ proto __ 和constructor是对象独有的,prototype是函数独有的;但是在js里函数也是对象,所以函数也有 __ proto __ 和constructor属性。
constructor对于引用类型来说是可以修改的,但是对于基本类型是只读的。
typeof 和 instanceof 原理
typeof 用于判断一个变量的类型,但是在判断object类型时,不能说明该object属于哪一种object
instanceof 用于监测constructor.prototype是否存在于参数object的原型连上
模拟实现new
关于new的模拟,首先需要知道会发生哪些事:
- 一个新对象被创建
- 调用其构造函数,并将this绑定到新创建的对象。
- 由构造函数返回的对象就是new表达式的结果
我们了解过一些关于原型、原型链知识点后知道一个实例可以:
- 访问到其构造函数(比如Foo)的属性
- 访问到其原型(比如Foo.prototype)的属性
function my_new() {
var obj = new Object() // 创建一个新对象
Con = [].shift.call(arguments) // 取出需要(外部传入的)的构造函数
obj.__proto__ = Con.prototype // 将obj的原型指向构造函数,这样obj就可以访问到构造函数的属性
var result = Con.apply(obj, arguments) // 使用apply,改变构造函数的this到新建的对象,这样obj就可以访问到构造函数的属性
return typeof result === 'object' ? result : obj // 确保返回的是个对象
}
关于继承:
借用构造函数继承:
原理:将父级的构造函数this指向了子级构造函数的实例上
局限: 父级的原型链并没有被子级改变
function Mydad() {
this.fatherName = 'hi dad'
console.log('dad的this' , this)
}
function Mychild() {
Mydad.call(this)
console.log('child的this' , this)
}
Mydad.prototype.sayHi = function(){
console.log('hi you~~~')
};
var child1 = new Mychild()
console.log(child1)
- 缺点 : 方法都在构造函数中定义,每次创建实例都会创建一遍方法,同时通过
Mydad.prototype.sayHi = function(){
console.log('hi you~~~')
};
这种方式,子级就没有办法继承
原型链继承
原理:通过prototype的让实例对象的原型指向父级
局限:
- 如果实例了两个对象,针对他们的引用类型的属性来说,更改了一个对象。另一个对象也会被改变(因为他们共用一个原型对象),如果不是引用类型的属性,就不会存在这个问题。
- 创建子级实例时,没法向父级传参
局限如下:
组合继承(第一版)
原型链继承和构造函数继承一起使用
缺陷:在实例子类的时候,父类构造函数执行了两次
优化组合继承(第二版)
原理:如果想要继承父类的原型对象,就直接给他父类的原型对象
缺陷:会造成子类实例对象直接指向父级原型
优化组合继承(第三版)
主要就是要把构造器指回自己,
Mychild.prototype = Object.create(Mydad.prototype) // 增加了一级__proto__相当于隔离了Mychild,Mydad
// 使用下面这种方式也可以
Child.prototype = new Parent(); // 但是如上说了,会执行两次
原型式继承
原理: ES5 Object.create 的模拟实现,将传入的对象作为创建对象的原型
缺陷: 包含引用类型的属性值会始终共享,跟原型链继承一样
function mychild(obj) {
function Mydad(obj) {
this.fatherName = 'hi dad'
}
Mydad.prototype = obj
return new Mydad()
}
var person = {
name: 'hahaha',
type: [999]
}
var child1 = mychild(person)
var child2 = mychild(person)
child1.type.push(333)
console.log(child1)
console.log(child2)
寄生式继承
原理:创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。类似于借用构造函数一样,每次创建对象都会创建一遍方法
function mychild(obj) {
var clone = Object.create(obj); // 创建一个新对象
clone.sayName = function () {
console.log('hi'); // 以某种方式来增强这个对象
}
return clone; // 返回这个对象
}
var person = {
name: 'hahaha',
type: [999]
}
var child1 = mychild(person)
var child2 = mychild(person)
child1.type.push(333)
console.log(child1)
console.log(child2)
寄生式继承就是对原型继承的扩展,可以新增自己的方法和属性