js的中对象高级部分理解vue的双向数据绑定,以及创建对象 --- 设计模式

对象

含义:无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来讲,对象是一组没有特定顺序的值,那么它肯定是一个引用数据类型。

对象的属性类型

es5定义了只有内部才用的特性(attribute)时,描述了属性(property原型)的各种特征。 es5 这些特性是为了实现JavaScript 引擎用的,因此在 Js 中不能直接访问它们;

js属性有两种: 数据属性和访问器属性

1. 数据属性( 4个特性)

  1. [Configurable] Boolean 能否通过 delete 删除属性(默认true)
  2. [Enumerable] Boolean 能否通过 for-in 循环返回属性(默认true)
  3. [Writable] Boolean 能否修改属性的值(默认true)
  4. [Value] Boolean 包含这个属性的数据值(默认值是undefind)

使用 Object.defineProperty() 方法,修改属性的默认行为 ;
接受参数(属性所在的对象、属性的名字,一个描述符对象)描述符(descriptor)对象的属 性必须是:
configurable、
enumerable、
writable 和
value 设置其中的一或多个值

ps1: 多次调用 Object.defineProperty()方法修改同一个属性,在把 configurable 特性设置为 false
之后就会有限制了

var people = {};
Object.defineProperty(people, 'name', {
  configurable: false
});
people.name = '12';
console.log(people);   // undefined 

在这里插入图片描述

ps2: 调用 Object.defineProperty()设置空对象的属性时,如果不指定,configurable、enumerable
和 writable 特性的默认值都是 false

    console.log(Object.prototype);
    var people = {};
    Object.defineProperty(people, 'name', {});
    people.name = '12';
    console.log(people);   // undefind

在这里插入图片描述

访问器属性(包含一对儿 getter 和 setter 函数)
在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值
写入访问器属性时,会调用 setter 函数并传入新值,这个函数负责决定如何处理数据
有4个特性
[Configurable] Boolean 能否通过 delete 删除属性(默认true)
[Enumerable] Boolean 能否通过 for-in 循环返回属性(默认true)
[Get]: 在读取属性时调用的函数。默认值为 undefined
[Set]:在写入属性时调用的函数。默认值为 undefined

访问器属性不能直接创建, 必须使用 Object.defineProperty() 来定义

var book = {
  _year: 200,
  edit: 1
};
Object.defineProperty(book, 'year', {
  get: function() {
    return this._year;
  },
  set(newValue) {
    if (newValue > 2004) {
      this._year = newValue;
      this.edit = newValue - 2004;
    }
  }
});
book.year = 2008;
console.log(book);

Vue的双向数据绑定 就是 Object.defineProperty( ) 方法搞的
来简单说下vue的原理

  1. 通过document.createDocumentFragment()创建虚拟DOM
  2. 会通过Object.defineProperty定义的数据拦截,截取到数据的变化。
  3. 通过订阅—发布者模式,触发Watcher(观察者),从而改变虚拟dom的中的具体数据
  4. 通过更新虚拟dom的元素值,改变最终渲染dom元素的值,完成双向绑定

关于 document.createDocumentFragment() 方法
在这里插入图片描述

创建对象 - 设计模式

参考红皮书啊,这里不做任何解释, 就是让你看看其实你平时在写代码的时候也用到了设计模式,还有一面试 人家问点设计模式就不知道是啥!

工厂模式

说白了,就跟你自己封装方法一样,最后返回一个对象,可能你都已经写过这种模式了

function createPeople(name, age) {
  var o = new Object();
  o.name = name;
  a.age = age;
  o.say = function() {
    return this.name;
  };
  return o;
}
//  实例化对象
var p1 = new createPeople('里斯', 12);
var p2 = new createPeople('大钟', 16);

构造函数模式

构造函数是定义在 Global 对象(在浏览器中是 window 对象)中的,经常写吧,如果不知道,那es6 的class 你见过吧!

function Animal(name, age) {
  this.name = name;
  this.age = age;
  this.say = function() {
    return this.name + ' : ' + this.age;
  };
}

//  ps 一个面试题
// 要创建 Animal 的新实例,必须使用 new 操作符。调用构造函数实际上会经历以下 4 个步骤:
// (1) 创建一个新对象;
// (2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
// (3) 执行构造函数中的代码(为这个新对象添加属性);
// (4) 返回新对象

/**
 *  构造函数当作函数
 * 1. 构造函数与其他函数的唯一区别,就在于调用它们的方式不同
 * 2. 任何函数,只要通过 new 操作符来调用,那它就可以作为构造函数
 * 3. 任何函数,不通过 new 操作符来调用,那它跟普通函数也不会有什么两样
 */
//  构造函数实例化调用  => 使用dog

var dog = new Animal('狗', 12);
dog.say();

// 普通调用  => 使用window
Animal('猫', 2);
console.log(window.say());

// 在另一个对象的作用域中调用
var s = {};
Animal.call(s, '狐狸', 2);
console.log(s.say());

寄生构造函数模式

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

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

原型模式

  • 创建的每个函数都有一个 prototype(原型)属性,
  • 这个属性是一个指针,指向一个对象,
  • 而这个对象的 包含 所有实例共享的属性和方法
function Person() {}
Person.prototype.name = 'jooker';
Person.prototype.age = 19;
Person.prototype.say = function() {
  return this.name;
};

var p = new Person();
console.log(p.__proto__=== Person.prototype)
console.log(p.constructor === Person)
console.log(Person.prototype.constructor === p.constructor)

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

function Person(name) {
  this.name = name;
  this.friends = ['Shelby', 'Court'];
}
Person.prototype = {
  constructor: Person,
  sayName: function() {
    return this.name;
  }
};
var person1 = new Person('Nicholas');

var person2 = new Person('Greg');

person1.friends.push('Van');

console.log(person1.friends); //"Shelby,Count,Van"
console.log(person2.friends); //"Shelby,Count"

动态原型模式

 function Person(name,age){
   this.name = name;
   this.age = age;
   // 方法
   if(typeof this.sayName != "function"){
     Person.prototype.sayName = function(){
       return this.name;
     }
   }
 }
 var p = new Person("Nick",25);
 console.log(p.name)
 console.log(p.age)
 console.log(p.sayName())

稳妥构造函数模式

function Add(a, b) {
  var o = new Object();
  o.say = function() {
    return a;
  };
  return o;
}
var sum = Add(1,2);
console.log(sum.say())

ECMAScript 中的函数是对象,因此每定义一个函数,也就是实例化了一个对象
(prototype: 显式原型 ,proto : 隐式原型, 原型链:也叫隐式原型链)
还有就是要知道一点,js中的原型,原型链,上下文,是代码在宿主环境中运行时才确定的,而作用域,是在你写代码时就确定的

理解原型对象

  1. 每当创建 一个新函数,就会根据规则为该函数创建一个 prototype 属性,指向函数的原型对象 (即函数一旦创建,先在内部执行了一步 this.proterty = { })
  2. 默认情况下,所有原型对象都会自动获得一个 constructor (构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针 (函数的 原型的 构造函数 === 实例对象的 构造函数)
  3. 通过这个 prototype 可以在原型上添加方法和属性
  4. 创建自定义的函数后, 它的原型对象 默认只有一个 constructor 属性 ,而其它的方法则是从 Object 继承来的
  5. 创建实例之后,该实例的 内部 将包含一个指针(proto:隐式原型),指向 构造函数的 原型对象 (prototype:显式原型) (也就是说,一旦你实例化创建一个对象,会先添加一个内部的 proto
    属性,这是每个对象都有的)
发布了63 篇原创文章 · 获赞 100 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/qq_36407748/article/details/88027077