创建对象:ES5 VS ES6
ES5:
- 字面量
- Object
- 构造函数
<script>
// 1. 利用 new Object() 创建对象
var obj1 = new Object();
// 2. 利用 对象字面量创建对象
var obj2 = {};
// 3. 利用构造函数创建对象
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh);
ldh.sing();
zxy.sing();
</script>
ES6:
class方式
class name {
// class body
}
var xx = new name();
这两种方式创建对象的结果以及内部的原型链都一样,只是ES6的写起来简单很多,class name,name的本质还是function,一个函数。
下面讲讲ES5创建对象的原型链。
静态成员和实例成员的区别:
静态成员:只能在构造函数本身上添加的成员,只能通过构造函数本身来访问
实例成员:只能在构造函数内部是创建,只能通过实例化对象来访问。
为什么会有原型链?
当我们使用构造函数时,实例化的对象有共同的方法时,
就会占用的不是同一块内存,浪费空间。
原型链就是把所有共同的方法都集中在一起,所有实例化的对象都从他这里调用。共享内存。
这是构造函数,实例化对象,原型链之间的关系。
原型链:
JS的成员查找机制
优先级是:对象实例 > star构造函数 > star原型对象 > Object原型对象。
this指向问题:
原型对象和构造函数的this都指向对象实例。
拓展内置对象
只能用Array.prototype.sum = function() {} ,不能用覆盖式的Array.prototype = 。。。。这样来写。
比如实例化,var ldh = new Star();
因为我们的原型对象.contructor
是指向我们的Star的,Star.prototype 就是原型对象,当我们添加方法时。太多的方法我们就用。
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象
//,则必须手动的利用constructor指回原来的构造函数
constructor: Star,
sing: function() {
console.log('我会唱歌');
},
movie: function() {
console.log('我会演电影');
}
}
采取赋值来添加,这样就覆盖了constructor,就不能正确指向我们的构造函数,所以在上面我们要手动赋值。
继承
ES5并没有给我们提供extends来继承,我们就采取构造函数+原型对象的“组合继承”。
通过call(参数1(this指向),参数2(正常参数),参数3…)方法。把父类的this指向子类型的this。
继承属性
<script>
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
var son = new Son('刘德华', 18, 100);
console.log(son);
</script>
继承方法
<script>
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题
//,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor
//指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
</script>
原理:
- 将共享方法提取出来,
Son.prototype = new Father();
- 本质是开辟新的空间,不影响父类正常的原型对象。
- 再将constructor指回 son
上图的Son原型对象也有constructor指回Son构造函数
下面是不开辟新空间的后果
这样的话,Son和Father的原型对象就是占同一个空间,会有不好的后果,一修改则全修改。