Hibop.github.io icon indicating copy to clipboard operation
Hibop.github.io copied to clipboard

关于对象创建和对象继承之N中方法

Open Hibop opened this issue 7 years ago • 2 comments

1. 创建对象:

  1. new Object()
var person = new Object();
pserson.name = 'ifyour';
person.age = 18;
person.sayName = function() {
    console.log(this.name);
}
  1. 字面量
vaer person = {
    name: 'ifyour',
    age: 18,
    sayName: function(){
        console.log(this.name);
    }
}
  1. 工厂模式
function createPerson(name, age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        console.log(this.name);
    }
    return o;
}
  1. 构造函数模式: new Object是构造函数的特殊
function Person(name, age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name);
    }
}
var person = new Person('ifyour', 18);
person.sayName(); // => ifyour

注意: 箭头函数无法new 创建

  1. 原型模式
function Person(){
}

Person.prototype.name = 'ifyour';
Person.prototype.age = 18;
Person.prototype.sayName = function(){
    console.log(this.name);
}

var person1 = new Person();
var person2 = new Person();
person1.sayName(); // => ifyour
console.log(person1.sayName == person2.sayName); // => ture
  1. Object.create()创建 Object.create与new区别:
  • 1.Object.create传入对象将作为新建对象的原型。
  • 2.Object.create传入构造函数原型时,无论构造函数是否返回对象,Object.create只会return 以构造函数原型来新建的对象(参见下面的polyfill),而new则会返回return的obj对象。
  1. class语法糖,extend, super()等

对象继承

  1. 原型链继承:重写原型对象,使子类原型对象指向父类的实例(包括私有和共享原型)以实现继承。
function Person(){
	this.age = 20;
}
Person.prototype.getPersonAge = function(){
	console.log( this.age );
}
function Student(){
	this.name = "zhangsan";
}
// 继承 Person
Student.prototype = new Person();
Student.prototype.constructor = Student; // 注意此处注释很重要,Student.prototype上有constructor指向Student构造函数,重写后需要重新挂载,否则构造函数指向Person
let zhangsan = new Student();
zhangsan.getPersonAge();    // 20

缺点: 不能向父类传参; 改变一个子类实例会影响到其他

  1. 构造函数(call继承):解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫叫做借用构造函数(constructor stealing)的技术(有时候也叫做伪造对象或经典继承)。 这种技术的基本思想相当简单,即在子类构造函数内部调用父类构造函数,但是需要结合apply()和call()方法改变this指向同时执行。
function Person(name, age){
	this.name = name;
	this.age = age;
	this.sayName = function(){
		console.log( this.name );
	}
}
// call继承只会继承父类的实例私有属性,而不会继承原型上属性;可否Person.prototype.call(this)【答案: 不行, 因为call是函数方法】
Person.prototype.getPersonAge  = function() {
}

function Student(name, age){
	// 继承 Person
	Person.call(this, name, age);
	// Person.apply(this, [name, age]);
}
let zhangsan = new Student("zhangsan", 22);
zhangsan.sayName();    // zhangsan

也会有一个问题:子类无法继承父类定义在原型身上的属性和方法。 ,属性和方法都需要在构造函数内部定义。但是这样函数的复用就无从谈起了,并且每个对象实例都会保存相同的方法,这种方式也会造成内存的浪费。考虑到这些问题,借用构造函数的技术也是很少单独使用的。

  1. 遍历继承(也叫拷贝继承, 冒充继承): 其实就是遍历父类实例,拿来给子类

  2. 组合(混合)继承: 有时候也叫做伪经典继承,指的是将原型链和借用构造函数的 技术组合到一块,从而发挥二者之长的一种继承模式。实现的思路就是:使用原型链实现对原型身上的方法的继承,同时通过借用构造函数来实现对实例属性的继承。

function Person(name, age){
	this.name = name;
	this.age = age;
}
Person.prototype.sayName = function(){
	console.log( this.name );
}
// 通过借用构造函数继承实例的属性
function Student(name, age){
	Person.call(this, name, age);
}
// 通过原型链继承原型的方法
Student.prototype = new Person();
let zhang = new Student("zhangsan", 22);
zhang.sayName();

问题: 调用两次父类构造函数

优化型 6. 中间件继承 子类的私有实例: Parent.call(this, ...arguments) 子类的共享实例: Child.prototype = Parent.prototype

7 Es 6 Class-extends继承 区别: es5继承: 实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。 不能继承原生对象Array... es6 的继承机制完全不同: 实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。 可以继承原生对象Array...

class A extends B {
  constructor(...arg) {
     // 此处调用this报错
     super(...arg) // A.prototype.constructor.call(this)
     // 可以调用this了
   } 
}

es5每个对象有__proto__属性, 每个函数有protoype属相 Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。 Child.proto === Parent 表示构造函数的继承,总是指向父类构造函数 : child作为对象 child.prototype.proto === Parent.prototype 表示实例方法的继承,指向父类的原型 : child作为构造函数 实现原理

Object.setPrototypeOf(Child.prototype, Parent.prototype);
Object.setPrototypeOf(Child,  Parent);

image image

Hibop avatar Jan 14 '18 16:01 Hibop

重新理解JS的6种继承方式: http://www.cnblogs.com/ayqy/p/4471638.html

Hibop avatar Jan 23 '18 10:01 Hibop

function Fun(){
    // 私有属性
    var val = 1;        // 私有基本属性
    var arr = [1];      // 私有引用属性
    function fun(){}    // 私有函数(引用属性)
 
    // 非原型实例,私有属性
    this.val = 1;               // 实例私有基本属性
    this.arr = [1];             // 实例私有引用属性
    this.fun = function(){};    // 实私有例函数(引用属性)
}
 
// 原型共享属性
Fun.prototype.val = 1;              // 原型基本属性
Fun.prototype.arr = [1];            // 原型引用属性
Fun.prototype.fun = function(){};   // 原型函数(引用属性)

Hibop avatar Jan 23 '18 10:01 Hibop