原型继承
原型继承是JS中最常用的一种继承方式,
子类B想要继承父类A中的所有的属性和方法(私有+共有),只需要让B.prototype=new A;即可
特点:把父类中私有的+共有的都继承到了子类的原型上(子类共有的)
例如:
function A() {
this.x = 100;
}
A.prototype.getX = function () {
console.log(this.x);
};
function B() {
this.x = 200;
}
B.prototype = new A;
示意图:
核心:原型继承并不是把父类中的属性和方法克隆一份一模一样的给B,而是让B和A之间增加了原型链的连接,以后B的实例n想要A中的getX方法,需要一级一级的向上查找来使用
如果继续执行这句代码:n.x = 1000;
修改的是n的私有属性,与其他无影响
如果继续执行:n.__proto__.x
= 2000;
修改A的实例上的属性,对B的实例、n都有影响,但是对A及实例没有影响
如果继续执行:n.__proto__.__proto__.getX
= 2000;
修改A的原型上的方法,对所有都有影响,该过程叫方法的重写
#div1.__proto__
->HTMLDivElement.prototype->HTMLElement.prototype->Element.prototype->Node.prototype->EventTarget.prototype->Object.prototype
模拟上述过程;
function myObject() {}
myObject.prototype = {
constructor: myObject,
hasOwnProperty: function () {}
};
function myEventTarget() {}
myEventTarget.prototype = new myObject;
myEventTarget.prototype.addEventListener = function () {};
function myNode() {}
myNode.prototype = new myEventTarget;
myNode.prototype.createElement= function () {};
var n = new myNode;
console.dir(n);
n.constructor = A;
故需增加:B.prototype.constructor = B;
call继承
call继承的最终结果是把父类私有的属性和方法克隆一份一模一样的作为子类私有的属性,与父类没有关系。
function A() {
this.x = 100;
}
A.prototype.getX = function () {
console.log(this.x);
};
function B() {
//this是n
A.call(this); //把A执行,让A中的this变成n
}
var n = new B;
console.log(n.x); //100
冒充对象继承
把父类私有的加公有的克隆一份一模一样的给子类私有的,与父类无关
function A() {
this.x = 100;
}
A.prototype.getX = function () {
console.log(this.x);
};
function B() {
var temp = new A;
for (var key in temp) {
//console.log(key); //x getX
this[key] = temp[key];
}
temp = null;
}
var n = new B;
console.log(n.x); //100
混合模式继承
原型继承+call继承
私有的变成私有的,私有的加公有的变成公有的
私有的重复了
function A() {
this.x = 100;
}
A.prototype.getX = function () {
console.log(this.x);
};
function B() {
A.call(this); //相当于n.x=100
}
B.prototype = new A; //相当于在原型上既有x=100,也有getX
B.prototype.constructor = B;
var n = new B;
console.log(n.x); //100
寄生组合式继承(create考虑兼容)
私有的只拿私有的(call)
公有的只拿公有的(create)
function A() {
this.x = 100;
}
A.prototype.getX = function () {
console.log(this.x);
};
function B() {
A.call(this);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
var n = new B;
console.log(n.x); //100
中间类继承(__proto__
考虑兼容)
function avgFn() {
arguments.__proto__ = Array.prototype;
}
avgFn(12,234,24,23);
让arguments使用数组中的方法
1.每一个函数数据类型(普通函数类)都有一个天生自带的属性:prototype(原型),并且这个属性是一个对象数据类型的值
2.并且在prototype上浏览器天生给他加了一个属性constructor(构造函数),属性值是当前函数(类)本身
3.每一个函数数据类型也天生自带一个属性proto,属性值是当前实例所属类的原型(prototype)
创建一个对象的两种方式:
var obj = {}; 字面量方式
var obj = new Object(); 构造函数方式/实例创建方式
两种方式没有区别
var num = 1; 基本数据类型的数字1
var num = new Number(1); 对象数据类型
两种方式有区别
for-in循环在遍历的时候,默认可以把自己私有的和在它所有类原型上拓展的属性和方法都可以遍历到,但是,一般情况下,只需要遍历私有的即可,可以使用以下的判断进行处理:
可枚举的:obj.propertyIsEnumerable()
Object.prototype.aaa = function () {
};
var obj = {name: "abc", age: 2};
for (var key in obj) {
if (obj.propertyIsEnumerable(key)) {
console.log(key); //name age
}
}
或者:
Object.prototype.aaa = function () {
};
var obj = {name: "abc", age: 2};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key); //name age
}
}
如果没有可枚举:
Object.prototype.aaa = function () {
};
var obj = {name: "abc", age: 2};
for (var key in obj) {
console.log(key); //name age aaa
}
Object.create(proObj)
创建一个新对象,但是还要把proObj作为这个对象的原型
IE6-8中不兼容
var obj = {
getX: function () {
}
};
var obj2 = Object.create(obj);
//obj2是对象数据类型
//__proto__:
// getX:function...
// __proto__:Object.prototype
obj2.getX();
obj.getY = function () {
console.log(2);
};
obj.getY(); //能够输出2
模拟obj.create():
创建一个类,并且让这个类的原型指向传进来的对象,返回类的实例,得到新的对象就指向传进来的值
function object(o) {
function Fn() {
}
Fn.prototype = o;
return new Fn;
}