填坑-十万个为何?(4)

简介:不少概念不清或忘记,从新构建本身的知识体系。天天问本身1~多个问题。我是菜鸟 成为大神之路!html

1. JavaScript建立对象的方法?

①语法结构建立的对象使用{},[]数组

var o = {name: "Lis",sex:16};     | o 这个对象继承了Object.prototype上面的全部属性
                                  | 
var arr = ["yo", "whadup", "?"];  | 数组都继承于 Array.prototype (Array.prototype 中包含 indexOf, forEach等方法)
                                  | 
function fun(){                   | 函数都继承于Function.prototype (Function.prototype 中包含 call, bind等方法)
  return 2;                       |
}                                 | 
复制代码

②构造器建立的对象使用new
在 JavaScript 中,构造器其实就是一个普通的函数。当使用 new 操做符 来做用这个函数时,它就能够被称为构造方法(构造函数)bash

function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v){
    this.vertices.push(v);
  }
};

var obj = new Graph();
obj是生成的对象,他的自身属性有'vertices''edges'.
在obj被实例化时,obj.[[Prototype]]指向了Graph.prototype.
复制代码

Object.create 建立的对象>>link
ECMAScript 5中引入了一个新方法。新对象的原型就是调用 create方法时传入的第一个参数。app

class 关键字建立的对象
ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不一样的。JavaScript 仍然基于原型。这些新的关键字包括 class, constructor,static,extends 和 superide

"use strict";

class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

class Square extends Polygon {
  constructor(sideLength) {
    super(sideLength, sideLength);
  }
  get area() {
    return this.height * this.width;
  }
  set sideLength(newLength) {
    this.height = newLength;
    this.width = newLength;
  }
}

var square = new Square(2);
复制代码

2. JavaScript继承的实现方法?

// 定义一个交通工具类
function Vehicle() {
  // 属性
  this.name;
  this.number;
  // 实例方法
  this.funBase = function(){
    console.log("交通工具名称:"+this.name+"||"+"可乘坐人数:"+this.number);
  }
}
// 原型方法
Vehicle.prototype.funRatio = function(ratio) {
  console.log(this.name + ':' + ratio);
};
复制代码
①原型链继承★★

核心: 将父类的实例做为子类的原型函数

function Car(){
    this.getName = function(){
        console.log(this.name);
        return this.name;
    }
};
function Airplane(){
    this.getName = function(){
        console.log(this.name);
        return this.name;
    }
};

Car.prototype = new Vehicle();
Car.prototype.name = '汽车';
Car.prototype.number = '20人';

Airplane.prototype = new Vehicle();
Airplane.prototype.name = '飞机';
Airplane.prototype.number = '100人';

var car = new Car();
var airplane = new Airplane();
//测试
car.funBase();
car.funRatio("60%");
car.getName();
airplane.funBase();
airplane.funRatio("36%");
airplane.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
复制代码

执行结果: 工具

特色:
* 很是纯粹的继承关系,实例是子类的实例,也是父类的实例
* 父类新增原型方法/原型属性,子类都能访问到
* 简单,易于实现
缺点:
* 要想为子类新增属性和方法,必需要在new Animal()这样的语句以后执行,不能放到构造器中
* 没法实现多继承
* 来自原型对象的全部属性被全部实例共享(来自原型对象的引用属性是全部实例共享的)(详细请看附录代码: 示例1)
* 建立子类实例时,没法向父类构造函数传参

'推荐指数:★★(三、4两大体命缺陷)'
复制代码
②构造继承★★

核心:使用父类的构造函数来加强子类实例,等因而复制父类的实例属性给子类(没用到原型)性能

function Car(){
  Vehicle.call(this);
  this.name = '汽车';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}

// 测试
var car = new Car();
car.funBase();
car.funRatio("60%");//TypeError: car.funRatio is not a function[详细了解]
car.getName();
console.log(car instanceof Vehicle); // false
console.log(car instanceof Car); //true
复制代码

执行结果 测试

特色:
* 解决了1中,子类实例共享父类引用属性的问题
* 建立子类实例时,能够向父类传递参数
* 能够实现多继承(call多个父类对象)
缺点:
* 实例并非父类的实例,只是子类的实例
* 只能继承父类的实例属性和方法,不能继承原型属性/方法
* 没法实现函数复用,每一个子类都有父类实例函数的副本,影响性能

'推荐指数:★★(缺点3)'
复制代码
③实例继承★★

核心:为父类实例添加新特性,做为子类实例返回ui

function Car(){
  var vehicle = new Vehicle();
  vehicle.name = '汽车';
  vehicle.number = '20人';
  vehicle.getName = function(){
        console.log(vehicle.name);
        return vehicle.name;
    }
    return vehicle;
}

// 测试
var car = new Car();
car.funBase();
car.funRatio("60%");//TypeError: car.funRatio is not a function[详细了解]
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //false
复制代码

执行结果:

特色:
* 不限制调用方式,无论是new 子类()仍是子类(),返回的对象具备相同的效果
缺点:
* 实例是父类的实例,不是子类的实例
* 不支持多继承

'推荐指数:★★'
复制代码
④拷贝继承★

核心:逐一复制父类实例的属性方法给子类实例

function Car(){
  var vehicle = new Vehicle();
  for(var p in vehicle){
    Car.prototype[p] = vehicle[p];
  }
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}

// 测试
Car.prototype.name = '汽车';
Car.prototype.number = '20人';
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); //false
console.log(car instanceof Car); //true
复制代码

执行结果:

特色:
* 支持多继承
缺点:
* 效率较低,内存占用高(由于要拷贝父类的属性)
* 没法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

'推荐指数:★(缺点1)'
复制代码
⑤组合继承★★★★

核心:经过调用父类构造,继承父类的属性并保留传参的优势,而后经过将父类实例做为子类原型,实现函数复用

function Car(){
  Vehicle.call(this);
  this.name = '汽车';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}
Car.prototype = new Vehicle();
Car.prototype.constructor = Car;//组合继承也是须要修复构造函数指向

// 测试
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
复制代码

执行结果:

特色:
* 弥补了方式2的缺陷,能够继承实例属性/方法,也能够继承原型属性/方法
* 既是子类的实例,也是父类的实例
* 不存在引用属性共享问题
* 可传参
* 函数可复用
缺点:
* 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

'推荐指数:★★★★(仅仅多消耗了一点内存)'
复制代码
⑥寄生组合继承★★★★

核心:经过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

function Car(){
  Vehicle.call(this);
  this.name = '汽车';
  this.number = '20人';
  this.getName = function(){
        console.log(this.name);
        return this.name;
    }
}
(function(){
  // 建立一个没有实例方法的类
  var Super = function(){};
  //设置原型
  Super.prototype = Vehicle.prototype;
  //将实例做为子类的原型
  Car.prototype = new Super();
  // 须要修复下构造函数
  Car.prototype.constructor = Car; 
})();

// 测试
var car = new Car();
car.funBase();
car.funRatio("60%");
car.getName();
console.log(car instanceof Vehicle); // true
console.log(car instanceof Car); //true
复制代码

执行结果:

特色:
* 堪称完美
缺点:
* 实现较为复杂

'推荐指数:★★★★(实现复杂,扣掉一颗星)'
复制代码

3. Function.prototype.call() 实现继承时的原理?(相关apply()、bind()方法的使用)

①call()、apply()、bind() 都是用来重定义 this 这个对象的!
②参数:
* call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面  obj.myFun.call(db,'成都', ... ,'string' );
* apply的全部参数都必须放在一个数组里面传进去  obj.myFun.apply(db,['成都', ..., 'string' ]);
* 
③方法:
* apply:调用一个对象的一个方法,用另外一个对象替换当前对象。例如:B.apply(A, arguments);即A对象'应用'B对象的方法。
* call:调用一个对象的一个方法,用另外一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象'调用'B对象的方法。
复制代码

参考文章:
www.cnblogs.com/humin/p/455…
www.cnblogs.com/lengyuehuah…

相关文章
相关标签/搜索