构造函数与原型对象

构造函数

函数也可以作为构造函数的参数

  • 构造函数和工厂函数的区别:

    1. 构造函数首字母大写
    2. 构造函数内部会默认创建新的对象,并且默认返回这个对象
    3. 在创建对象的时候,通过new调用构造函数
  • 返回值

    • 构造函数内部没有return,返回默认新创建的对象
    • 如果构造函数内部有return,分两种情况:

      1. 返回值类型忽略该return,返回新创建的对象
      2. 返回值是引用类型的数据,会覆盖之前创建的对象,返回该引用类型数据的值
        1
        2
        3
        4
        5
        6
        7
        function Person(name, age) {
        this.name = name;
        this.age = age;
        //return 'test'; 会忽略该return
        //return {}; 返回该对象
        }
        var p1 = new Person('张三', 20);
  • 实例和实例化
    使用构造函数创建对象的过程称为实例化,创建出来的这个对象叫做该构造函数的实例

    基本包装类型

    StringNumberBoolean

  • 可以使用var str = new String('字符串')来创建字符串对象,这里typeof str //object
  • var str1 = '字符串'或者var str2 = String('字符串')的类型都是string
  • 我们还可以通过 var str = new Object('字符串')来创建字符串对象,也可以输入数字或true/false,Object会自动判断是哪种类型。这里typeof str //object

基本数据类型也能有属性或者方法,在内部会进行

  1. 创建一个与之对应的对象
  2. 利用这个对象访问属性和方法并返回结果
  3. 返回结构之后,立即销毁该对象
    var str = 'demo'; console.log(str.length); //4

this

this指向的是 函数的调用者 或者是 事件的调用者

this ->指向具体的对象
函数调用:

  1. 作为对象的方法调用 this->当前的对象
  2. 普通函数调用 this->window
  3. 通过new构造函数调用 this->构造函数内部创建的新对象
  4. 使用call / apply调用(函数上下文调用) this->第一参数

this在事件指令表示事件源
this在定时器中表示windows

new

我们经常利用new运算符去声明新的对象

new运算符接受一个函数F及其参数: new F(arguments…)
这一过程分为三步:

  1. 创建类的实例。这步是把一个空的对象的__proto__属性设置为F.prototype。
  2. 初始化实例。函数F被传入参数并调用,关键字this被设定为该实例。
  3. 返回实例,如果没有return,默认返回this引用。

new 运算符的作用是创建一个实例对象。这个对象可以是用户自定义的,也可以是带构造函数的一些系统自带的对象。

new 运算符可以让 this 指向新的对象

所谓“构造函数”,其实就是普通函数内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
为了和普通函数区分, 第一个字母大写

例如:

1
2
3
4
5
6
7
8
9
function fun() {
alert(this); //this指向window
}
fun();
function fn() {
alert(this); //this指向fn
}
new fn(); //添加了new的函数,this指向的是新的对象

私有方法和特权方法

私有变量/方法:定义在构造函数内部的变量和方法,私有方法本身是可以访问构造函数内部的所有属性的,即私有属性和共有属性。但是私有方法不可以在构造函数的外部被调用。

1
2
3
4
5
6
function Fun() {
var private = '私有变量';
funciotn privateFun() {
console.log('这是一个私有方法');
}
}

特权方法:可以当问私有变量和私有函数的实例方法,使用this.来转换。

1
2
3
4
5
6
7
8
9
function Fun() {
this.name = '名字';
this.showName = funciotn () {
//通过this定义一个特权方法
console.log(this.name);
}
}
var obj = new Fun();
obj.showName(); //名字


原型对象(prototype)

  • 什么是原型对象?

    在构造函数创建出来的时候,系统会默认创建一个对象和这个构造函数关联,这个对象就称为这个构造函数的原型对象

  • 原型对象的作用?

    使用构造函数创建的对象默认就可以使用原型对象中的属性方法

  • 怎么访问原型对象?

    构造函数.prototype
    对象.__prototype__

    注意:`__prototype__`不是ECMA标准里的属性
    
  • 怎么设置原型对象?
    1. 原型对象本质也是对象,利用对象的动态特性也可以设置原型对象的属性和方法
    2. 使用字面量的方式创建(替换原型)

关于原型对象的替换

  1. 替换原型对象之前所创建的对象替换之后创建的对象,它们的原型对象不是同一个原型对象。(切断)
  2. 替换原型对象之后,constructor指向Object,需要在替换时修正构造器的指向
1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(){} //创建构造函数
var p1 = new Person(); //创建对象
var obj = {
/*修正时需要加一段代码,
constructor : Person,
指向原来的原型对象,这样之前创建的对象才能正确使用新的属性方法*/
des : '一段描述'
}
//替换原型对象
Person.prototype = obj;
var p2 = new Person();
console.log(p1.des); //undefined 替换之前没有des属性
console.log(p2.des); //一段描述

原型对象的属性

  1. 访问原型对象的属性

    • 对象.属性
    • 构造函数.prototype.属性
  2. 属性的访问原则
    就近原则: 使用对象.属性访问属性的时候,首先会去找自己身上的属性(实例属性),如果找到就返回该值,如果没有,会去该对象构造函数原型对象上找是否有这个属性(原型属性)。如果都没有,返回undefined或报错(函数)。

  3. 设置原型对象的属性

    1. 通过构造函数.prototype.属性来设置换着替换原型对象属性
    2. 如果属性是引用类型的数据,可以通过实例对象.引用对象.属性的方式修改

      关于实例对象中的属性与原型对象中的属性

      虽然能通过实例对象访问原型对象中的值,但不能通过实例对象重写原型中的值,当为实例对象添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,换句话说,添加的这个属性只会阻止我们访问原型中的那个属性,但不会对原型中属性产生任何影响。不过使用delete操作符可以完全删除实例属性,从而让我们可以重新访问原型中的属性。

属性存在的检测

  • for..in: 判断对象中是否存在指定的属性。既可以检测实例属性也可以检测原型属性。
  • hasOwnProperty()方法 :判断对象中是否存在指定的实例对象中。

补充:对象(Object)数据类型

对象就是带有属性方法数据类型

例如 ArrayDate等,我们最常用的Function也是一个对象,虽然

`typeof function(){}; //"function"`

但是Function实例和其他类型的实例没有什么区别,都是对象,只不过 typeof 操作符对其做了特殊处理