构造函数
JavaScript 的构造函数中可以添加一些成员 可以在构造函数上本身添加 也可以在构造函数内部的this上添加 通过这两种方式 添加成员 就分别称为 静态成员和实例成员
- 静态成员: 在构造函数身上添加的成员 称为静态成员 只能由构造函数本身访问
- 实例成员: 在构造函数内部创建的对象成员 称为实例成员 只能由 实例化的对象来访问
原型对象
构造函数的方法很好用 但是存在浪费内存的问题
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age
this.sing = function () {
console.log('构造函数的问题');
}
}
var ldh = new Star('刘德华', 18)
var zxy = new Star('张学友', 18)
// 在内存中开辟的是 两个空间 地址是不一样的
console.log(ldh.sing === zxy.sing); //返回false
我们可以是所有的对象 共同使用同一个函数 这样比较节省内存
构造函数原型 prototype
构造函数通过原型分配的函数是所有对象共享的
JavaScript 规定 每一个构造函数都有一个 prototype 属性 指向另一个对象 注意这个prototype 就是一个对象 这个对象的所有属性 的方法 都会被构造函数所拥有
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age
// this.sing = function () {
// console.log('构造函数的问题');
// }
}
Star.prototype.sing = function () {
console.log('构造函数原型');
}
var ldh = new Star('刘德华', 18)
var zxy = new Star('张学友', 18)
ldh.sing()
zxy.sing()
console.log(ldh.sing === zxy.sing); // true
// 一般情况下 我的公共属性 定义到构造函数内部里面
// 公共的方法 我们放到原型对象里边
原型是什么?
- 一个对象 我们也称为prototype为原型对象
原型的作用是什么
- 共享方法
对象原型 __ proto__
每个实例对象(object)都有一个私有属性(称之为 __ proto __ )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__ proto __),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
对象都会有一个属性 --proto-- 指向构造函数的prototype原型对象 之所以 我们对象可以使用构造函数prototype 原型对象的属性和方法 就是因为 对象有 __ proto __ 原型的存在
__ proto __ 对象原型 和 原型对象 prototype 是等价的
console.log(ldh.__proto__ === Star.prototype); // true
__ proto __ 对象原型 的意义就在于为对象的查找机制提供一个方向 或者说一条线路 但 它是一个非标准属性 因此在开发中 不可以使用这个属性 它只是内部指向原型对象.prototype
方法查找规则
首先看ldh 对象身上是否有sing这个方法 如果有就执行这个对象上的sing
如果有sing这个方法 因为有 __ proto__的存在 就去构造函数原型对象prototype身上去查找sing这个方法
constructor 构造函数
对象原型 __proto__和构造函数 prototype 原型对象 里面都有一个属性 constructor 属性 constructor 我们成为构造函数 因为它指回构造函数本身
console.log(Star.prototype.constructor); // 返回的 是构造函数本身
console.log(ldh.__proto__.constructor);
如果修改了原来的原型对象 给原型对象赋值的是一个对象 则 必须手动的利用 constructor 指回原来的构造函数
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age
// this.sing = function () {
// console.log('构造函数的问题');
// }
}
// Star.prototype.sing = function () {
// console.log('构造函数原型');
// }
Star.prototype = {
// 如果修改了原来的原型对象 给原型对象赋值的是一个对象 则 必须手动的利用 constructor 指回原来的构造函数
constructor: Star,
sing: function () {
console.log('唱歌');
},
movie: function () {
console.log('演电影');
}
}
var ldh = new Star('刘德华', 18)
var zxy = new Star('张学友', 18)
ldh.sing()
zxy.sing()
// 在内存中开辟的是 两个空间 地址是不一样的
console.log(ldh.sing === zxy.sing); //返回false
console.log(ldh);//对象身上系统自己添加了一个 __proto__ 指向我们的构造函数的原型对象 prototype
console.log(ldh.__proto__ === Star.prototype); // true
// 方法查找规则 首先看ldh 对象身上是否有sing这个方法 如果有就执行这个对象上的sing
// 如果有sing这个方法 因为有 __proto__的存在 就去构造函数原型对象prototype身上去查找sing这个方法
console.log(Star.prototype.constructor); // 返回的 是构造函数本身
console.log(ldh.__proto__.constructor);
// console.dir(Star);
</script>
构造函数 实例 原型对象三者之间的 关系
原型链
只要是对象都有 原型 __ proto __
javaScript 的成员查找机制(规则)
- 当访问一个对象的属性(包括方法)时 首先查找这个对象自身有没有该属性
- 如果没有就查找它的原型(也就是__ proto __指向的的prototype原型对象)
- 如果还没有就查找原型对象的原型 (Object 的原型对象)
- 一次类推一直找到Object 为止(null)
扩展内置对象
可以通过原型对象 对原来的内置对象进行扩展自定义的方法 比如给数组增加自定义求偶数的功能
<script>
console.log(Array.prototype);
Array.prototype.sum = function () {
var sum = 0
for (var i = 0; i < this.length; i++) {
sum = sum + this[i]
}
return sum
}
var arr = [1, 2, 3];
console.log(arr.sum());
console.log(Array.prototype);
</script>