前端面试题积累

建立对象的方式

一、工厂模式javascript

在函数里,new 一个 Object,而后根据传入的参数给该对象添加属性,最后返回该对象。问题:没法知道一个对象的类型。java

二、构造函数模式数组

问题:每一个方法都要在每一个实例上从新建立一遍。解决:在全局做用域中定义全局函数。固然,这会致使封装性不好。app

三、原型模式函数

每一个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象(指向该函数的原型对象),而这个对象的用途是包含能够由特定类型的全部实例共享的属性和方法。若是按照字面意思来理解,那么 prototype 就是经过调用构造函数而建立的那个对象实例的原型对象。使用原型对象的好处是可让全部对象实例共享它所包含的属性和方法。this

缺点:原型中全部属性是被不少实例共享的,这种共享对于函数很是合适。可是对于包含引用类型值的属性问题就突出了spa

四、组合使用构造函数模式和原型模式prototype

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。
结果,每一个实例都会有本身的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。指针

五、动态原型模式code

在构造函数中这么写共享的方法和属性:

// 方法
if (typeof this.sayName != 'function') {
  Person.prototype.sayName = function() {
    alert(this.name);
  };
}

六、寄生构造函数模式

基本思想:建立一个函数,该函数的做用仅仅是封装建立对象的代码,而后再返回新建立的对象。

function Person(name, age, job) {
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function() {
    alert(this.name);
  };
  return o;
}

var friend = new Person('Amy', 18, 'student');
friend.sayName();    // Amy

构造函数在不返回值的状况下,默认会返回新对象实例。而经过在构造函数的末尾添加一个 return 语句,能够重写调用构造函数时返回的值。

用法:这个模式能够在特殊的状况下用来为对象建立构造函数。假设咱们想建立一个具备额外方法的特殊数组。因为不能直接修改 Array 构造函数,所以可使用这个模式。

function SpecialArray() {
  // 建立数组
  var values = new Array();
  // 添加值
  values.push.apply(values, arguments);
  // 添加方法
  values.toPipedString = function() {
    return this.join('|');
  };
  // 返回数组
  return values;
}

var colors = new SpecialArray('red', 'green', 'blue');
alert(colors.toPipedString());    // red|green|blue

关于寄生构造函数模式,有一点须要说明:
首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部建立的对象没有什么不一样。为此,不能依赖 instanceof 操做符来肯定对象类型。

用 new 调用构造函数实际经历了4个步骤

  • 1 建立一个新对象;
  • 2 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象);
  • 3 执行构造函数中的代码(为这个新对象添加属性);
  • 4 返回新对象。

理解原型对象

全部函数都有一个 prototype 属性,这个属性指向函数的原型对象

在默认状况下,全部原型对象都会自动得到一个 constructor (构造函数)属性,这个属性是一个指向 prototype 属性所在函数的指针
eg. Person.prototype.constructor => Person。

当调用构造函数建立一个新实例后,该实例的内部将包含一个指针(内部属性[[Prototype]]),指向构造函数的原型对象。注意:这个链接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。实例 => 构造函数的原型对象

原型对象

判断某个实例的原型指针是否指向某个函数的原型对象:

Person.prototype.isPrototypeOf(person1)    // true
Object.getPrototypeOf(person1) === Person.protype    // true

hasOwnProperty() 方法:检测一个属性是存在于实例中,仍是存在于原型中。只有存在于实例中时,才返回 true。
in 操做符:实例和原型中的属性都能访问到。
同时使用 hasOwnProperty() 方法和 in 操做符,就能够肯定该属性究竟是存在于对象中,仍是存在于原型中。

Object.keys() 方法:取得对象上全部可枚举的实例属性。
Object.getOwnPropertyNames() 方法:获得全部实例属性(包括不可枚举属性)。

重写原型会怎么样?

Person.prototype = {…}:
咱们将 Person.prototype 设置为等于一个以对象字面量形式建立的新对象。 最终结果相同,但有一个例外:constructor 属性再也不指向 Person 了。前面曾经介绍过,每建立一个函数,就会同时建立它的 prototype 对象,这个对象也会自动得到 constructor 属性。而咱们在这里使用的语法,本质上彻底重写了默认的 prototype 对象,所以 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),再也不指向 Person 函数。此时,尽管 instanceof 操做符还能返回正确的结果,但经过 constructor 已经没法肯定对象的类型了。

重写原型对象

实现继承的方式

一、原型链继承

相关文章
相关标签/搜索