JavaScript 的原型链
JavaScript 的原型链关系到js 的对象,方法实例化的原理,弄懂原型链就可以明白 js 封装继承的原理.对理解js 的面向对象有很大的帮助.在 ES6 中引入了 class 关键字,但那只是语法糖,JavaScript 仍然是基于原型链的.
原型链主要是由 2 个对象实现的: __proto__
和 prototype
__proto__和 prototype
JavaScript 的所有对象都有__proto__
这个属性,其实__proto__
就是一个指针, 他指向实例化他这个对象的原始对象的 prototype 对象.
1 | class Book {} // function Book() {} |
prototype 是所有的函数对象都有的属性,当一个函数对象被 new 实例化时,他的 prototype 里的属性和方法都会被复制一份,放到实例化的对象里,并且 prototype 这个对象也有__proto__
对象,实例化的时候还会把__proto__
指向的对象的 prototype 里的属性和方法也复制一份.也就实现了继承.
1 | class Book {} |
JavaScript 的基本数据类型
JavaScript 的基本数据类型也是通过这种方法实现的.
1 | const a = 1; // const a = new Number(1); |
这个时候 a 和 str 就是 Number 和 String 函数(方法,类)的实例化对象.
1 | a.__proto__ === Number.prototype; |
而这些数据类型又都是 Object 对象的子类.
1 | Number.prototype.__proto__ === Object.prototype |
如果你写一个类继承于 Number,例如 class Int extend Number{}
那么这个类的实例化对象就会有
1 | class Int extend Number{} |
经过测试
1 | Function.prototype.__proto__ === Object.prototype; // true |
所以 JavaScript 的数据类型都是 Object 类型的子类,所以说 JavaScript 的所有数据都是对象
而原型链的终点就是 null
关于函数: JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处。
由于函数与其他数据类型地位平等,所以在 JavaScript 语言中又称函数为第一等公民。
construction 方法
构造方法,也就是实例化对象时(new)调用的方法.这个方法其实就是一个类的名字指向的地址.
1 | Number.prototype.constructor === Number; // true |
而实例化之后的对象也拥有 construction 方法,他指向他的类
1 | const a = 1; |
这样就可以更容易判断一个对象他由哪个类实例化而来了
new 运算符
new运算符的原理:
- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的prototype属性。
- 将这个空对象赋值给函数内部的this关键字。
- 开始执行构造函数内部的代码。
1 | function _new(/* 构造函数 */ constructor, /* 构造函数参数 */ params) { |
Object.create()
构造函数作为模板,可以生成实例对象。但是,有时拿不到构造函数,只能拿到一个现有的对象。我们希望以这个现有的对象作为模板,生成新的实例对象,这时就可以使用Object.create()方法。
1 | var person1 = { |
原型链的作用
在面向对象编程中,子类会继承父类的方法和属性,当一个属性在子类的实例化对象中找不到时,就会去找他父类的属性.JavaScript 的原型链也是这样工作的,查找一个对象的属性或者方法,就会去他的__proto__
指向的prototype 中找,如果还没有,就会去 prototype.__proto__指向的 prototype 中找,一直找到 Object.prototype.这也就实现了类的继承.