三个概念
- 构造函数 / 原型对象 / 实例对象
以内置对象Array为例,Array是用于构造数组的全局对象。Array构造函数创建的实例数组对象可以继承使用所有Array.prototype的属性和方法。 - 每个函数都有一个prototype属性,指向一个对象。
function Phone(name,size){
this.name = name;
this.size = size;
this.info = '4G';
this.main = ['camera','NFC','blueteeth','line'];
this.call = function(){
console.log('don\'t forget call me plz')
}
};
Phone.prototype.send = function(){
console.log('send message to her')
}
var phone = new Phone('samsung',5.8);
console.log(phone.name + phone.size);
phone.call();
phone.send();
构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子。
var world = new Func()
命令的过程:
- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的prototype属性。
- 将这个空对象赋值给函数内部的this关键字。
- 执行构造函数内部的代码。
JS继承
- 原型链继承,用一个实例对象a覆盖构造函数本来指向的原型对象,此时该构造函数生成的实例对象x就可以访问a的实例方法和a的原型对象A的属性和方法
- 原型链继承的缺点,如果一个实例不小心修改了原型对象上引用类型的值,会导致其它实例也跟着受影响。(当实例中存在和原型对象上同名的属性时,加载实例对象的值。)
function Iphone(name,size){
this.name = name;
this.size = size;
}
Iphone.prototype = new Phone();
var iphone = new Iphone('8 Plus');
console.log(iphone.info); // 4G
iphone.call(); // don't forget call me plz
iphone.send(); // send message to her
- 构造函数继承,子类的构造函数中,通过
apply ( )
或call ( )
的形式,调用父类构造函数,子类构造函数每实例化一个对象(a和b),相当于父类构造函数新生成一个对象(x1和x2,两个一样的副本) - 每个子类实例都会拷贝一份父类构造函数中的方法,作为实例自己的方法。方法过多的时候,占用内存大。当需求改变,要改动其中的一个方法时,之前所有的实例,他们的该方法都不能及时作出更新。
Person.call(this)
代表:stu1 去调用 Person 方法时,Person 内部的 this 指向就指向了 stu1(正常情况下this所指是新建的空对象,this.name = Jack
,现在是stu1.name = Jack
)。那么Person 内部this 上的所有属性和方法,都被拷贝到了 stu1 上,stu2 也是同理。
- 借用构造函数的方式可以在子类型的构造函数中向超类型构造函数传递参数。
- 为了确保子类型的熟悉不会被父类的构造函数重写,可以在调用父类构造函数之后,再添加子类型的属性。
function Oppo(name){
this.name = 'myname';
this.info = '5G';
Phone.call(this,name);
// this.info = '5G'; 写在父类构造函数后面才能覆盖父类的属性
};
var oppo1 = new Oppo('oppo1');
oppo1.main.push('finger');
console.log(oppo1.name);
console.log(oppo1.info); // 4G
console.log(oppo1.main);
// [ 'camera', 'NFC', 'blueteeth', 'line', 'finger' ]
var oppo2 = new Oppo('oppo2');
console.log(oppo2.name);
console.log(oppo2.main);
// [ 'camera', 'NFC', 'blueteeth', 'line' ]
- 组合继承,把公有的方法挂载到父类的原型对象上,既能保证子类实例对象有各自的引用对象副本(构造函数),也能避免父类公有方法太多时产生的问题(原型链)。
function Huawei(name){
this.name = name;
Phone.call(this);
}
Phone.prototype.takePhoto = function(){
console.log('take a picture');
}
Phone.prototype.weChat = function(){
console.log('caht with your friend');
}
Huawei.prototype = new Phone();
Huawei.prototype.constructor = Huawei;
var honor1 = new Huawei('honor1');
console.log(honor1.name);
honor1.takePhoto();
honor1.main.push('finger');
console.log(honor1.main);
var honor2 = new Huawei('honor2');
console.log(honor2.main);
-
深 / 浅拷贝
-
引用对象 / 值对象
-
复制数组:
arr.slice()
该方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:
如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。 -
this
-
call / apply / bind
-
实例对象的__proto__属性(前后各两个下划线),返回该对象的原型
-
获取实例对象obj的原型对象的方法
参考
http://javascript.ruanyifeng.com/oop/basic.html
https://www.cnblogs.com/sarahwang/p/9098044.html
https://blog.csdn.net/liuyan19891230/article/details/50774439