一、普通对象与函数对象
凡是通过 new Function()创建的对象都是函数对象(包括直接用function定义的函数对象和字面量定义的函数对象),其他的都是普通对象(Object、Function是JS自带的函数对象)。
函数对象:
function func1() {}
var func2 = function() {};
var func3 = new Function();普通对象
var obj = {};
var obj2 = new Object();
var obj3 = new func1();
二、prototype与__proto__
在javascript中,每当定义一个对象(函数)的时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个prototype属性,这个属性指向函数的原型对象。(普通对象没有prototype属相,只有 __proto__ 属性)
原型对象就是普通对象(Function.prototype除外,因为它没有prototype属性。),原型对象就是该函数对象的一个实例。
function Animal() {}
var cat = new Animal();
此处的函数对象就是Animal,原型对象就是Animal.prtotype。
javascript在创建对象的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype
cat.__proto__ == Animal.prototype;
Aniaml.prototype.__proto__ == Object.prototype;
而Obect.prototype对象的__proto__属性等于null。
而所有函数对象的__proto__属性都指向Function.prototype,它是一个空函数
Number.__proto__ === Function.prototype;
String.__proto__ === Function.prototype;
.
.
.
三、constructor
在默认情况下,所有的原型对象都会自动获得一个constructor属性,它是一个指向prototype属性所在的函数的指针。
Animal.prototype.constructor == Animal;
cat.constructor == Aniaml;
constructor的值是一个函数,在javascript中,除了null 和undefined外的类型的 值、数组、函数以及对象 都有一个constructor属性,constructor的值就是这个 值、数组、函数或者对象的 构造函数
var num = 17;
var str = 'string1';
num.constructor //Number()
str.constructor //String()
.
.
.
四、引用类型
在javascript的7中数据类型中(包括ES6的symbol),只有对象时引用类型的值,其余为基本类型的值。
引用类型的值(对象)是引用类型的一个实例。对象时某个特定引用类型(也就是某个特别对象)的一个实例。新对象是使用new操作符 后跟一个构造函数来创建的。而构造函数本身就是一个函数(即一个函数对象)。
var obj = new Object();
引用类型的值不仅可以是Object,也可以是Array、Date、Function等
var arr = new Array();
因为typeof Array 的值为 “function”
五、原型继承
1.引用原型继承存在的问题
function Parents() {}
Parents.prototype.name = "father";
Parents.prototype.getName = function() {
return this.name;
}
//子类继承
function Generator() {}
Generator.prototype = Parents.prototype;
Generator.prototype.name = "son"; //修改原型属性
Generator.prototype.constructor = Generator;
此时,Generator通过引用来继承Parents的属性,它们的引用指向了同一个内存空间,所以一旦修改了Generator的属性,Parents的属性也会受到影响。
为了解决父对象不受子对象修改的影响,使用临时构造器的方法。
首先创建一个临时构造器,当做一个中间变量,接着创建一个空函数,并将它的原型设置为父级的一个构造器,然后new一个中间变量(函数)来创建一个不包含父级属相的对象,同时又能从父级的prototype中继承父级的属性。
function Parents() {};
Parents.prototype.name = "father";
Parents.prototype.getName = function() {
return this.name;
}
//创建临时构造器
var MiddleWare = Function();
MiddleWare.prototype = Parents.prototype;
//子对象
function Son() {};
Son.prototype = new MiddleWare();
Son.prototype.constructor = Son; //将构造器指向自己
Son.prototype.name = "son"; //修改属性
var son = new Son();
console.log(son.getName()); //son
var parent = new Parents();
console.log(parent.getNmae()); //father
2.浅拷贝
子对象拷贝父对象,父对象中的成员有对象变量时,子对象拷贝父对象的引用,若修改子对象,父对象的值也会受到影响。
var person = {
name: "name",
score: {math: 107,chinese: 118,english: 123}
};
var student = {age: 21};
function extend(first,second) {
var second= second|| {};
for(var prop in first) {
second[prop] = first[prop];
}
}
extend(person,student); //拷贝
//修改子对象属性
studnet.score.math = 117;
console.log(person.score[math]); //117;
此时,父对象中score.math的值也被修改了。
3.深拷贝
为了解决父对象总的引用属相不被修改,使用深拷贝来实现。
若父对象中的属性是对象或者是数组,对其做特殊处理:递归
function extendDeeply(first,second) {
var second = second || {};
for(var prop in first) {
if(typeof first[prop] === "Object") {
second[prop] = (first[prop].constructor === Array) ? [] : {};
extendDeeply(first[prop],second[prop]);
} else {
second[prop] = first[prop];
}
}
}
也可以使用call来实现
function Parent() {
this.name = "father";
this.job = {one: "washing",tow: "running"}
}
function Son() {
Parent.call(this);
this.age = 21;
}