构造函数继承
- 继承:子类继承父类所有属性和行为,父类不受影响。
- 目的:找到类之间的共性精简代码
//构造函数继承只能继承对象内部方法
function Person(name){
this.name = name;
this.eyes = "两只";
this.legs = "两条";
}
function Student(name){
Person.call(this,name);
// Person.apply(this,[name]);
// Person.bind(this)(name);
this.className = "二班";
}
let newPerson = new Student("张三");
console.log(newPerson.className);
为了实现原型的继承可以使用原型的赋值
- 但是简单原型继承,出现影响父类的情况;
function Dad(height){
this.name = "张三";
this.age = 20;
this.height = height;
this.money = "$1000000";
}
Dad.prototype.hobby = function(){
console.log("喜欢高尔夫");
}
function Son(height){
Dad.call(this,height);
// Dad.apply(this,[height])
// Dad.bind(this)(height);
}
Son.prototype = Dad.prototype //直接赋值
Son.prototype.hobby = function(){
console.log("篮球");
}
let newSon = new Son("178cm");
// console.log(newSon);
newSon.hobby(); // 篮球
let newDad = new Dad("179cm");
newDad.hobby(); //篮球
//输出两个都是显示篮球,父类方法被覆盖了继承方法不可靠
- 组合继承 修改子类原型的指向,添加一个构造函数做为媒介
function Dad(){
this.name = "张三";
}
Dad.prototype.hobby = function(){
console.log("高尔夫");
}
function Son(){
Dad.call(this);
}
let F = function(){}
F.prototype = Dad.prototype;
Son.prototype = new F(); // 新开辟内存地址
Son.prototype.constructor = Son;
Son.prototype.hobby = function(){
console.log("篮球");
};
let newSon = new Son("178cm");
// console.log(newSon);
newSon.hobby(); // 篮球
let newDad = new Dad("179cm");
newDad.hobby(); //高尔夫
原型的深拷贝继承
-
传值和传址问题
- 基本数据类型:Number、String、Boolean、Null、Undefined 拷贝不存在传值问题
- 复杂数据类型/引用数据类型:Array、Date、Math、RegExp、Object、Function等存在拷贝传值问题
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 b 改版没有影响a 的值
let obj = {
name: "张三",
age: 20,
arr: [1, 2, 3],
obj3: {
},
test: undefined,
fn: function () {
console.log("fn...");
},
test2: null
}
let obj2 = obj;
obj2.age = 30;
console.log(obj); /*{name: "张三", age: 30, arr: Array(3), obj3: {…}, test: undefined, …}
age: 30
arr: (3) [1, 2, 3]
fn: ƒ ()
name: "张三"
obj3: {}
test: undefined
test2: null
__proto__: Object*/
// 结果显示obj 属性age被修改了
- 采用JSON序列化拷贝对象
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.age = 30;
console.log(obj2);
/*{name: "张三", age: 30, arr: Array(3), obj3: {…}, test2: null}
age: 30
arr: (3) [1, 2, 3]
name: "张三"
obj3: {}
test2: null
__proto__: Object*/
console.log(obj); /* {name: "张三", age: 20, arr: Array(3), obj3: {…}, test: undefined, …}
age: 20
arr: (3) [1, 2, 3]
fn: ƒ ()
name: "张三"
obj3: {}
test: undefined
test2: null
__proto__: Object*/
-JOSN序列化的不足
如果拷贝对象包含函数,或者undefined等值,此方法就会出现问题
- 浅拷贝和深拷贝
//递归深拷贝
function deepCopy(obj){
let newObj = Array.isArray(obj)?[]:{};
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(typeof obj[key] == "object"){
newObj[key] = deepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
}
}
return newObj;
}
let obj2 = deepCopy(obj);
console.log(obj2);/*{name: "张三", age: 20, arr: Array(3), obj3: {…}, test: undefined, …}
age: 20
arr: (3) [1, 2, 3]
fn: ƒ ()
name: "张三"
obj3: {}
test: undefined
test2: null
__proto__: Object*/拷贝成功
- 深拷贝继承
function Dad(){
this.name = "张三";
}
Dad.prototype.hobby = function(){
console.log("高尔夫");
}
function Son(){
Dad.call(this);
}
Son.prototype = deepCopy(Dad.prototype); // 新开辟内存地址
Son.prototype.constructor = Son;
Son.prototype.hobby = function(){
console.log("篮球");
};
let newSon = new Son("178cm");
newSon.hobby(); // 篮球
let newDad = new Dad("179cm");
newDad.hobby(); //高尔夫
原型的继承
- 原型链是指对象在访问属性或方法时的查找方式。
1.当访问一个对象的属性或方法时,会先在对象自身上查找属性或方法是否存在,如果存在就使用对象自身的属性或方法。如果不存在就去创建对象的构造函数的原型对象中查找 ,依此类推,直到找到为止。如果到顶层对象中还找不到,则返回 undefined。
2.原型链最顶层为 Object 构造函数的 prototype 原型对象,给 Object.prototype 添加属性或方法可以被除 null 和 undefined 之外的所有数据类型对象使用。
function Drag(){
this.ele = "some value..."
}
Drag.prototype.ele = "prototype value....";
let drag1 = new Drag();
console.log(drag1.ele); // 输出some value...
function Drag(){
// this.ele = "some value..."
}
Drag.prototype.ele = "prototype value....";
let drag1 = new Drag();
console.log(drag1.ele); // 输出 prototype value....
function Drag(){
// this.ele = "some value..."
}
// Drag.prototype.ele = "prototype value....";
Object.prototype.ele = 'Object.value...';
let drag1 = new Drag();
console.log(drag1.ele); // 输出 Object.value...
ES6中的类
- 类的写法
class Person{
height="178cm";
constructor(name,age){
//属性
this.name = name;
this.age = age;
}
//方法
getName(){
console.log("姓名是:"+this.name);
}
}
let student = new Person("张三",20);
student.getName();
-
静态方法和属性:实例不会继承的属性和方法
class Person{ //静态方法 static hobby(){ console.log("喜欢篮球"); } } //静态属性 Person.height = "178cm"; //通过类来调用 Person.hobby(); console.log(Person.height);
-
类的继承:extends
class Dad{ name = "张三"; age = 40; constructor(height){ this.height = height; } hobby(){ console.log("喜欢篮球"); } } class Son extends Dad{ constructor(height){ //表示父类的构造函数 super(height); } } let son1 = new Son("178cm"); son1.hobby(); console.log(son1.height);
包装对象
- 除过null,undefined,基本类型都有自己对应的包装对象:String Number Boolean
- 包装对象把所有的属性和方法给了基本类型,然后包装对象消失
常用方法
- hasOwnProperty():看是不是对象自身底下的属性
- contructor查看对象的构造函数 可以用来做判断
- instanceof:对象与构造函数是否在原型链上有关系
- toString()判断类型; 转换字符串 进制转换