JS高程学习-第六章(二)---创建对象

1. Object
new Object()

缺点 使用同一个接口创建很多对象,产生大量代码

2.字面量
var  a= {b:c}

缺点 使用同一个接口创建很多对象,产生大量代码

3.工厂模式

原理 发明一种函数 封装特定接口 返回一个对象

优点 解决代码重复

缺点 无法解决对象识别的问题

function createPerson (name,age){
    var o = new Object();  
    o.name = name ; 
    o.age= age;  
    o.sayName = function(){
        alert(this.name);
    }
    
    return o;
}   
//多次调用 返回一个对象   无法识别这个对象是谁创建的

var person1 = createPerson('ss',10);
4.构造函数模式

原理 构造函数可以用来创建特定类型的对象

优点 特性 可以通过constructor 标识对象类型

缺点 构造函数中包含方法时 每生成一个新的对象 这个对象中就包含一个新的同名的方法(浪费内存) 实际上没有必要在 执行代码前就把 完成相同任务的方法 绑定在特定对象上

function Person (name,age){
    this.name = name ; 
    this.age= age; 
    this.sayName = function(){
        alert(this.name);
    }
}   

var person1 = new Person('ss',10); 
// 方法没有公用

//与工厂模式不同
1. 没有显示的创建对象
2. 直接将属性和方法赋值给 this 对象
3. 没有return 语句

new 操作符的运行过程

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象 (因此 this 指向这个对象)
  3. 执行构造函数代码
  4. 返回新对象

简单实现一个new

// 调用构造函数 

function create(Con, ...args) {
   //创建对象
  let obj = {}
 // 构造函数的原型 创建的对象进行原型关联  即为 对象的 __proto__  属性 指向原型对象
  // obj.__proto__ = Con.prototype;
  Object.setPrototypeOf(obj, Con.prototype)
  // 运行函数
  let result = Con.apply(obj, args)
  // 返回对象 
  return result instanceof Object ? result : obj
}

constructor(构造函数属性) : 用来标识对象类型

instanceof操作符 instanceof 并不关心构造函数,它真正关心的是原型链。

function B(){};
var A = new B();
console.log(A instanceof B);

沿着A的proto这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。

构造函数只要使用new 操作符 调用的就是构造函数 不使用它调用的时候 就是普通函数

5.原型模式

原理 每个函数都有一个prototype 的属性 , 此属性是一个指针,指向一个对象(包含特定类型的所有实例共享的属性和方法) 指向的对象 可以说是 实例的原型对象

优点 共享所有原型对象包含的属性和方法

缺点 原型中所有属性都是被很多实例所共享的, 但是基本类型的属性没有问题 但是所有实例同名引用属性的值都会指向一个地方

//
function Person () {
    Person.prototype.name = "p1";
    Person.prototype.age = 10;
    Person.prototype.sex = "female";
    Person.prototype.sayName =function(){
        console.log(this.name);
    }
}
/*
function Person () {
}

    Person.prototype.name = "p1";
    Person.prototype.age = 10;
    Person.prototype.sex = "female";
    Person.prototype.sayName =function(){
        console.log(this.name);
    }
    
    
------
function Person () {
}
// 重写  没有construtor
    Person.prototype= {
    //construtor:
        name : "p1",
        age : 10,
        sex : "female",
        sayName : function(){
            console.log(this.name);
        }
    }

*/

var per1 =new Person();
var per2 =new Person();
console.log(Person.prototype);

Person.prototype.isPrototyeOf(per1)
Person.prototype.isPrototyeOf(per2)

原型对象

  1. 任何时候只要创建新函数,就会为该函数创建一个prototype属性,此属性指向原型对象
  2. 所有原型对象自动获得一个construtor构造函数属性 其他方式 的这个值有嘛

isPrototypeOf 确定对象之间是否存在

getPrototypeOf 获取对象的_ proto _ 属性的值

原型链查找 从对象实例本身开始--原型对象

同名属性 不能被覆盖只能被屏蔽

hasOwnProperty 检测属性在原型中还是当前实例中

in只要能访问就返回true

5.组合使用构造函数和原型模式

此为最常见方法

原理

  1. 使用构造函数 定义实例专有属性
  2. 使用原型模式定义方法和共享属性

缺点 独立的构造函数和原型 不利于代码的可读性

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['aa', 'bb'];
}

Person.prototype = {
    constructor:Person,
    SayName : function(){
        alert(this.name);
    }
}

var person1 = new Person("zhangsan", 29, "Software Enginner");
var person2 = new Person("lisi", 31, "Doctor");

person1.friends.push('cc');
alert(person1.friends);    //aa, bb, cc
alert(person2.friends);    // aa, bb
alert(person1.friends === person2.friends);    //false
alert(person1.sayName === person2.sayName);  //true


6.动态原型模式

原理 通过构造函数初始化原型 有点像单例模式

缺点 独立的构造函数和原型 不利于代码的可读性

function Person (name, age, sex) {
    
    this.name = name;
    this.age = age;
    this.sex = sex;
    // 
    if(typeof this.sayName != "function"){  
        Person.prototype.sayName = function(){
            console.log(this.name);
        }
        Person.prototype.sayAge = function(){
            console.log(this.age);
        }
    }
}
var per = new Person("la", 19, "man");
7. 寄生构造函数模式

在前几种模式不适用的情况下 使用该模式

在特殊情况下为对象创建构造函数 ?

原理 创建一个函数,分装创建对象的代码,返回新对象 长得和工厂模式一模一样

8. 稳妥构造函数

没有公共属性,安全模式中使用 ,不适用this

9.es6 class

一种定义构造函数及其原型方法的语法糖


class MyClass {
  // class 方法
  constructor() { ... }
  method1() { ... }
  method2() { ... }
  method3() { ... }
  ...
}
  
  class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// 类是函数
alert(typeof User); // function

// ...或者,更确切地说是构造方法
alert(User === User.prototype.constructor); // true

// User.prototype 中的方法,比如:
alert(User.prototype.sayHi); // alert(this.name);

// 实际上在原型中有两个方法
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
// 测试枚举             
for(var a in u ){console.log(a)}             

Es5 实现

// 以纯函数的重写 User 类

// 1. 创建构造器函数
function User(name) {
  this.name = name;
}
// 任何函数原型默认具有构造器属性,
// 所以,我们不需要创建它

// 2. 向原型中添加方法
User.prototype.sayHi = function() {
  alert(this.name);
};

// 使用方法:
let user = new User("John");
user.sayHi();

// 访问器属性 es6

class User {

  constructor(name) {
    // 调用 setter
    this.name = name;
  }

  get name() {
    return this._name;
  }

  set name(value) {
    if (value.length < 4) {
      alert("Name is too short.");
      return;
    }
    this._name = value;
  }

}

let user = new User("John");
alert(user.name); // John

es5

Object.defineProperties(User.prototype, {
  name: {
    get() {
      return this._name
    },
    set(name) {
      // ...
    }
  }
});
             

区别

  1. 内部去呗
  2. 类方法不可枚举
  3. 类默认使用 use strict 在类构造函数中的所有方法自动使用严格模式。
  4. 可以直接写 访问器属性

学习整理

JS高程学习-第六章(一)---认识对象
JS高程学习-第六章(二)---创建对象
JS高程学习-第六章(三)---对象继承

你可能感兴趣的:(JS高程学习-第六章(二)---创建对象)