Giter VIP home page Giter VIP logo

blog's People

Watchers

 avatar  avatar

blog's Issues

闭包

引自JavaScript高程设计4中对闭包的定义:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。

理解对象

理解对象

对象是一组属性的无序集合,内容就是键值对,值可以是数据或者函数。

1.属性的类型

ECMA-262 使用一些内部特性描述属性的特征,这些特性由为 JavaScript 实现引擎的规范定义,因此开发者不能在 JavaScript 中直接访问这些属性。规范用两个中括号标记特性,如
[[Enumerable]]

属性分两种:数据属性和访问器属性

  1. 数据属性

数据属性包含一个保存数据值的位置。读写都在这个位置,数据属性有 4 个特性描述它们的行为:

  • [[Configurable]]:属性是否可以通过 delete 删除并重新定义,特性是否可修改,是否可改为访问器属性。默认为 true
  • [[Enumerable]]:属性是否可通过 for-in 循环返回,默认为 true
  • [[Writable]]:属性是否可修改,默认为 true
  • [[Value]]:包含属性实际的值。默认 undefined

可通过 Object.defineProperty()修改默认特性,如下

let person = {};
Object.defineProperty(person, "name", {
  writable: false,
  value: "mike",
});

configurable 设置为 false 后无法再通过 Object.defineProperty 定义特性。

  1. 访问器属性
  • [[Configurable]]:同上
  • [[Enumerable]]:同上
  • [[Get]]:获取函数,读取属性时调用。默认 undefined
  • [[Set]]:设置函数,写入属性时调用。默认 undefined

同样是通过 Object.defineProperty 定义,获取函数和设置函数不一定都有定义。只定义 get 意味着属性是只读的,尝试修改会被忽略

在调用 Object.defineProperty()时,未指定的特性默认为 false/undefined,访问器属性和数据属性不可同时定义

字面量新建的对象属性默认是数据属性

2. 定义多个属性

Object.defineProperties

3. 读取属性的特性

使用 Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述符。这个方法接受两个参数:属性所在的对象和要取得其描述符的属性名。返回值是一个对象,包含 configurable、enumberable、get 和 set 属性,对于数据属性包含 configurable、enumerable、writable 和 value 属性。

ECMAScript 2017 新增了 Object.getOwnPropertyDescriptions()静态方法。这个方法实际上会在每个自有属性上调用 Object.getOwnPropertyDescriptor()并在一个新对象中返回它们,如下

let person = {
  name: 11,
  age: 22,
};
Object.getOwnPropertyDescriptors(person);
{
    "name": {
        "value": 11,
        "writable": true,
        "enumerable": true,
        "configurable": true
    },
    "age": {
        "value": 22,
        "writable": true,
        "enumerable": true,
        "configurable": true
    }
}

let book = {}
Object.defineProperties(book,{
  year_:{
    value:2017
  },
  edition:{
    value:1
  },
  year:{
    get:function(){
      return this.year_
    },
    set:function(newValue){
      if(newValue>2017){
        this.year_=newValue
        this.edition += newValue - 2017
      }
    }
  }
})
Object.getOwnPropertyDescriptors(book);
{
    "year_": {
        "value": 2017,
        "writable": false,
        "enumerable": false,
        "configurable": false
    },
    "edition": {
        "value": 1,
        "writable": false,
        "enumerable": false,
        "configurable": false
    },
    "year": {
        "enumerable": false,
        "configurable": false,
        get: ƒ (),
        set: ƒ (newValue)
    }
}

4.合并对象

JavaScript 开发者经常觉得‘合并’(merge)两个对象很有用。更具体地说,就是把源对象所有的本地属性一起复制到目标对象上。有时候这种操作也被称为‘混入’(mixin),因为目标对象通过混入源对象的属性得到了增强。

ECMAScript6 专门为合并对象提供了 Object.assign()方法。这个方法接受一个目标对象和一个或多个源对象作为参数,然后将每个源对象中可枚举(Object.propertyIsEnumerable()返回 true)和自有(Obejct.hasOwnProperty()返回 true)属性复制到目标对象。以字符串和符号为键的属性会被复制。对每个符合条件的属性,这个方法会使用源对象上的[[Get]]取得属性的值,然后使用目标对象上的[[Set]]设置属性的值,不能在两个对象间转移获取函数和设置函数。

创建对象

创建对象

虽然使用 Object 构造函数或对象字面量可以方便地创建对象,但这些方式也有明显不足:创建具有同样接口的多个对象需要重复编写很多代码

1.概述

es5.1 并没有正式支持面向对象的结构,比如类和继承。但是,正如接下来几节会介绍的,巧妙地运用原型式继承可以成功地模拟同样的行为

es6 正式支持类和继承。es6 的类旨在完全涵盖之前规范设计的基于原型的继承模式。不过,无论从哪方面来看,es6 的类都仅仅是封装了 es5.1 构造函数加原型继承的语法糖而已。

2.工厂模式

抽象创建特定对象的过程。

function createPerson(name, age, job) {
  let o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function () {
    console.log(this.name);
  };
  return o;
}
let person1 = createPerson("Nicholas", 29, "Software Engineer");
let person2 = createPerson("Greg", 27, "Doctor");

这种工厂模式虽然可以解决多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)。

3.构造函数模式

ECMAScript 中的构造函数是用于创建特定类型对象的。如 Object、Array。当然也可以自定义构造函数,以函数的形式为自己的对象类型定义属性和方法。
上面的例子可改造如下

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    console.log(this.name);
  };
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas 10
person2.sayName(); // Greg

按照管理,构造函数的首字母是要大写的,只是为了区分构造函数和普通函数

要创建 Person 实例,应使用 new 操作符。以这种方式调用构造函数会执行如下操作。

  1. 在内存中创建一个新对象。
  2. 这个新对象内部的[[prototype]]特性被赋值为构造函数的 prototype 属性。
  3. 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象

上一个例子的最后,person1 和 person2 分别保存着 Person 的不同实例。这两个对象都有一个
constructor 属性指向 Person,如下所示:

console.log(person1.constructor == Person); // true
console.log(person2.constructor == Person); // true

constructor 本来是用于标识对象类型的。不过,一般认为 instanceof 操作符是确定对象类型更可靠的方式。(instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。)

定义自定义构造函数可以确保实例被标识为特定类型,相比于工厂模式,这是一个很大的好处。

构造函数也是函数

直接调用 Person,this 指向全局对象,可通过 call/apply 调用

构造函数的问题

构造函数定义的方法会在每个实例上都创建一遍。person1 和 person2 都有 sayName 方法,但却不是同一个实例。

解决方法:将函数定义转移到构造函数外部

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = sayName;
}
function sayName() {
  console.log(this.name);
}
let person1 = new Person("Nicholas", 29, "Software Engineer");
let person2 = new Person("Greg", 27, "Doctor");
person1.sayName(); // Nicholas
person2.sayName(); // Greg

这样虽然解决了相同逻辑的函数重复定义的问题,但是全局作用域也因此被搞乱,如果对象需要多个方法,全局作用域就要多定义这些函数,同时也会导致自定义类型引用的代码不能很好的聚集在以前。这个新问题可以通过原型模式来解决。

4. 原型模式

每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接复制给它们的原型,如下:

function Person() {}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
  console.log(this.name);
};
let person1 = new Person();
person1.sayName(); // "Nicholas"
let person2 = new Person();
person2.sayName(); // "Nicholas"
console.log(person1.sayName == person2.sayName); // true

过调用 hasOwnProperty()能够清楚地看到访问的是实例属性还是原型属性

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.