继承
继承发展史
- 传统形式 -->原型链
- 过多的继承了没用的属性
- 借用构造函数
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
function Student(name, age, sex, grade) {
Person.call(this, name, age, sex);
this.grade = grade;
}
var student = new Student();
- 不能继承借用构造函数的原型
- 每次构造函数都要多走一个函数
- 共享原型
Father.prototype.lastName = 'deng';
function Father() {
}
function Son() {
}
Son.prototype = Father.prototype;
var son = new Son();
console.log(son.lastName);// deng
- 不能随便改动自己的原型(修改之后父类的原型也会变动)
- 圣杯模式
Father.prototype.lastName = 'deng';
function Father() {}
function F() {}
F.prototype = Father.prototype;
Son.prototype = new F();
function Son() {}
var son = new Son();
console.log(son.lastName); // deng
- 可以封装成函数实现继承功能
Father.prototype.lastName = 'deng';
function Father() {}
function Son() {}
inherit(Son, Father);
var son = new Son();
var father = new Father();
console.log(son.lastName); // deng
console.log(father.lastName); // deng
// 再往子类的prototype上添加属性,不会改变父类的prototype
Son.prototype.sex = 'male';
console.log(son.sex); // male
console.log(father.sex); // undefined
function inherit(Target, Origin) {
function F() {};
F.prototype = Origin.prototype;
Target.prototype = new F();
// 防止子类构造函数指向父类构造函数
Target.prototype.constuctor = Target;
// 新建uber属性,指向集成的父类
Target.prototype.uber = Origin.prototype;
}
/*
下面为雅虎公司提供的工具包的写法,将函数F利用闭包的特性
实现属性私有化
*/
var YHinherit = (function () {
var F = function () {};
return function (Target, Origin) {
F.prototype = Origin.prototype;
Target.prototype = new F();
Target.prototype.constuctor = Target;
Target.prototype.uber = Origin.prototype;
}
}());
命名空间(不常用)
- 管理变量,防脏污染全局,适用于模块化开发
var org = {
department1: {
jicheng: {
name: 'abc',
age: 123
},
xuming: {
// ...
}
},
department1: {
// ...
}
}
var jicheng = org.department1.jicheng;
console.log(jicheng.name);
现在一般不用上面的方法
利用闭包对私有化变量,实现与命名空间相同的作用(常用)
var a = (function () {
var name = 'abc';
function callName() {
console.log(name);
}
return function () {
callName();
}
}())
var b = (function () {
var name = 'dfe';
function callName() {
console.log(name);
}
return function () {
callName();
}
}())
a();// abc
b();// def
补充:
实现方法的连续调用(模仿jQuery)
var deng = {
smoke: function () {
console.log('smoke......');
return this;
},
drink: function () {
console.log('drink......');
return this;
},
perm: function () {
console.log('perm......');
return this;
}
}
deng.smoke().smoke().drink().perm();
/*
smoke......
smoke......
drink......
perm......
*/
属性的表示方法
- obj.prop
- obj[‘prop’] (里面是字符串类型)
对象的枚举
for in循环遍历对象
var obj = {
name: '123',
age: 123,
sex: 'male',
height: 180,
weight: 75,
__proto__:{
lastName:'deng'
}
}
Object.prototype.a = 123;
// for in循环可以遍历对象的属性,包括自身属性和原型属性,
// 但是在遍历原型属性的时候只会遍历手动设置的属性,不会遍历系统的属性
for (var prop in obj) {
console.log(prop + ' ' + obj[prop]);
}
/*
name 123
age 123
sex male
height 180
weight 75
lastName deng
a 123
*/
for (var prop in obj) {
// hasOwnProperty("字符串")用于判断是否是自身属性,
// 如果不是自身属性或者是原型上的属性就返回false,自身的属性就返回true
if (obj.hasOwnProperty(prop)) {
console.log(prop + ' ' + obj[prop]);
}
}
/*
name 123
age 123
sex male
height 180
weight 75
*/
// in操作符用于判断属性是否属于这个对象,和hasOwnProperty()的区别在于:
// in不管是子类的属性还是继承自父类的属性都会返回true,
// 而hasOwnProperty()只有自身属性才返回true
console.log('age' in obj); // true
console.log('lastName' in obj); // true
// instanceof :A instanceof B:用于判断A是否是B构造函数构造出来的对象
// 更加深层次的理解:看A的原型链上有没有B的原型
function Person(){}
var person = new Person();
console.log(person instanceof Person); // true
console.log(person instanceof Object); // true
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true
三种方法判断一个变量是数组类型还是对象类型
- 构造函数不同
var obj = {};
var arr = [];
console.log(obj.constructor);// ƒ Object() { [native code] }
console.log(arr.constructor);// ƒ Array() { [native code] }
- 利用instanceof操作符
console.log(obj instanceof Array);// false
console.log(arr instanceof Array);// true
- 利用Object的toString()方法
console.log(Object.prototype.toString.call(obj));// [object Object]
console.log(Object.prototype.toString.call(arr));// [object Array]