面向对象和原型

理解原型

在JavaScript中,可通过原型实现继承。原型的概念很简单。每个对象都含有原型的引用,当查找属性时,若对象本身不具有该属性,则会查找原型上是否有该属性。

每个对象都可以有一个原型,每个对象的原型也可以拥有一个原型,以此类推,形成一个原型链。查找特定属性将会被委托在整个原型链上,只有当没有更多的原型可以进行查找时,才会停止查找。

对象构造器与原型

当用作为函数调用Ninja时,什么都不会做。在用new操作符时返回一个对象,并且设置了它的原型为Ninja,所以ninja2可以调用swingSword方法。但swingSword方法是Ninja的原型属性, 而不是ninja实例的属性

function Ninja(){}
Ninja.prototype.swingSword = function(){
return true;
};
const ninja1 = Ninja();
assert(ninja1 === undefined,
"No instance of Ninja created.");
const ninja2 = new Ninja();
assert(ninja2 &&
ninja2.swingSword &&
ninja2.swingSword(),
"Instance exists and method is callable." );

实例属性

  1. 当在原型和实例中有重名属性时,实例属性优先级比原型属性高
  2. 创建了多个实例,每个实例都是独立的拷贝,但是原型引用的是同一个方法
function Ninja(){
this.swung = false;
this.swingSword = function(){
return !this.swung;
};
}
Ninja.prototype.swingSword = function(){
return this.swung;
};
const ninja = new Ninja();
assert(ninja.swingSword(),
"Called the instance method, not the prototype method.");

通过构造函数实现对象类型

constructor

通过constructor属性来检查类型

assert(ninja.constructor === Ninja, constructor引用检测ninja的类型,得到的结果为其构造函数的引用

使用constructor的引用创建新对象

const ninja2 = new ninja.constructor(); ⇽--- 通过第1个实例化对象的constructor方法创建第2个实例化对象

实现继承

为了实现继承,将Person的实例作为Ninja的原型,所以当Niaja药调用person的方法时,将会沿着原型链进行查找。

function Person(){}
Person.prototype.dance = function(){};
function Ninja(){}
Ninja.prototype = new Person(); ⇽--- 通过将Ninja的原型赋值为Person的实例,实现Ninja继承Person
const ninja = new Ninja();
assert(ninja instanceof Ninja,
"ninja receives functionality from the Ninja prototype");
assert(ninja instanceof Person, "... and the Person prototype");
assert(ninja instanceof Object, "... and the Object prototype");
assert(typeof ninja.dance === "function", "... and can dance!")

重写constructor属性的问题

通过设置Person实例对象作为

Ninja构造器的原型时, 我们已经丢失了Ninja与Ninja初始原型之间的关联。

//通过defineProperty配置constructor对象
function Person(){}
Person.prototype.dance = function(){};
function Ninja(){}
Ninja.prototype = new Person();
Object.defineProperty(Ninja.prototype,"constructor",{
enumerable: false,
value: Ninja,
writable: true
}
);

在ES6使用JavaScript的class

ES6中使用关键字class来实现类,但其底层的实现仍然是基于原型继承!

使用class关键字

class Ninja{
constructor(name){
this.name = name;
}s
wingSword(){
return true;
}
//静态方法
static compare(ninja1, ninja2){
return ninja1.level - ninja2.level;
}
}

实现继承

class Person {
constructor(name){
this.name = name;
}
dance(){
return true;
}
}
class Ninja extends Person
constructor(name, weapon){
super(name); ⇽--- 使用关键字super调用基类构造函数
this.weapon = weapon;
}
wieldWeapon(){
return true;
}
}

控制对象的访问

使用getter与setter控制属性访问

//使用字面量get set
const ninjaCollection = {
ninjas: ["Yoshi", "Kuma", "Hattori"],
get firstNinja(){
report("Getting firstNinja");
return this.ninjas[0];
}, ⇽--- 定义firstNinja的getter方法, 返回ninjas列表中第一个值, 并记录一条
消息
set firstNinja(value){
report("Setting firstNinja");
this.ninjas[0] = value;
} ⇽--- 定义firstNinja的setter方法, 设置ninjas列表中第一个值, 并记录一条
消息
}; //ES6 class
class NinjaCollection {
constructor(){
this.ninjas = ["Yoshi", "Kuma", "Hattori"];
}
get firstNinja(){
report("Getting firstNinja");
return this.ninjas[0];
}
set firstNinja(value){
report("Setting firstNinja");
this.ninjas[0] = value;
} ⇽--- 在ES6的class中使用getter和setter
}
const ninjaCollection = new NinjaCollection();

使用getter与setter校验属性值

function Ninja() {
let _skillLevel = 0;
Object.defineProperty(this, 'skillLevel', {
get: () => _skillLevel,
set: value => {
if(!Number.isInteger(value)){
throw new TypeError("Skill level should be a number");
} ⇽--- 校验传入的值是否是整型。 如果不是, 则抛出异常
_skillLevel = value;
}
});
}
const ninja = new Ninja();

使用代理控制访问

可以将代理理解为通用化的setter与getter,区别是每个setter与getter仅能控制单个对象属性, 而代理可用于对象交互的通用处理,包括调用对象的方法

通过Proxy构造器创建代理

const emperor = { name: "Komei" };
const representative = new Proxy(emperor, {
get: (target, key) => {
report("Reading " + key + " through a proxy");
return key in target ? target[key]
: "Don't bother the emperor!"
},
set: (target, key, value) => {
report("Writing " + key + " through a proxy");
target[key] = value;
}
});

使用代理记录日志

function makeLoggable(target){
return new Proxy(target, {
get: (target, property) => {
report("Reading " + property);
return target[property];},
set: (target, property, value) => {
report("Writing value " + value + " to " + =property);
target[property] = value;
}
});
}
let ninja = { name: "Yoshi"};
ninja = makeLoggable(ninja);
assert(ninja.name === "Yoshi", "Our ninja Yoshi");
ninja.weapon = "sword"; ⇽--- 对代理对象进行读写操作时, 均会通过代理方法记录日志

使用代理可以优雅地实现以下内容。

  • 日志记录。
  • 性能测量。
  • 数据校验。
  • 自动填充对象属性(以此避免讨厌的null异常) 。
  • 数组负索引。

读Secrets of the JavaScript Ninja(二)对象的更多相关文章

  1. 读Secrets of the JavaScript Ninja(一)函数

    理解JavaScript为什么应该作为函数式 在JavaScript中,函数是程序执行过程中的主要模块单元 函数是第一类对象 通过字面量创建 function ninjaFunction(){} 赋值 ...

  2. [在读]Secrets of the javascript Ninja

    很棒的一本,可惜没有中文版.

  3. 《Secrets of the JavaScript Ninja》:JavaScript 之运行时代码

    最近,在阅读 jQuery 之父 John Resig 力作:Secrets of the JavaScript Ninja(JavaScript忍者秘籍).关于第九章提及的 JavaScript 之 ...

  4. 一、JavaScript概述 二、JavaScript的语法 三、JavaScript的内置对象

    一.JavaScript的概述###<1>JavaScript的概念 又称ECMAScript,和java没有任何关系 嵌入在HTML元素中的 被浏览器解释运行的 一种脚本语言. ###& ...

  5. 二、JavaScript语言--JS基础--JavaScript进阶篇--JavaScript内置对象

    1.什么事对象 JavaScript 中的所有事物都是对象,如:字符串.数值.数组.函数等,每个对象带有属性和方法. 对象的属性:反映该对象某些特定的性质的,如:字符串的长度.图像的长宽等: 对象的方 ...

  6. 2、JavaScript 基础二 (从零学习JavaScript)

     11.强制转换 强制转换主要指使用Number.String和Boolean三个构造函数,手动将各种类型的值,转换成数字.字符串或者布尔值. 1>Number强制转换 参数为原始类型值的转换规 ...

  7. JavaScript三(对象思想)

    JavaScript并不是面向对象的程序设计语言,但它是基于对象的.JavaScript中的每个函数都可用于创建对象,返回的对象既是该对象的实例,也是object的实例 . 一.对象与关联数组 Jav ...

  8. 学习javascript数据结构(二)——链表

    前言 人生总是直向前行走,从不留下什么. 原文地址:学习javascript数据结构(二)--链表 博主博客地址:Damonare的个人博客 正文 链表简介 上一篇博客-学习javascript数据结 ...

  9. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

随机推荐

  1. Ofbiz项目学习——阶段性小结——删除数据

    一.根据主键进行删除 /** * 按主键进行删除 * @param dctx * @param context * @return */ public static Map<String,Obj ...

  2. NSFileHandle类和NSFileManager,追加数据的操作

    NSFileHandle类主要对文件内容进行读取和写入操作 NSFileManager类主要对文件的操作(删除.修改.移动.复制等等) 常用处理方法 + (id)fileHandleForReadin ...

  3. React Virtual DOM Explained in Simple English

    If you are using React or learning React, you must have heard of the term “Virtual DOM”. Now what is ...

  4. 实现:python3_解析shodan_json数据

    前言:今天,一美元可以开通shodan,急忙去买了一个哈哈!! 下载json格式的数据,可以通过该脚本进行解析,得到相应的ip:port的格式 示例代码: # coding=utf-8 import ...

  5. 【JVM】内存和SWAP问题

    一.现象 1.系统稳定运行,偶尔发生响应超时的情况.查看下游依赖服务和数据库状态都良好.超时完全是由于服务本身问题造成的.重启不能解决问题,一直会间隔性的发生超时 二.原因分析 第一种情况,系统内存够 ...

  6. go语言 函数return值的几种情况

    分三种情况 (以下 “指定返回值”这句话, 仅指return后面直接跟着的返回值) 退出执行,不指定返回值 (1) 函数没有返回值 package main import ( "fmt&qu ...

  7. sql 将字符串转化为table

    /* *参数说明: 第一个参数为要转化的字符串,第二个参数为字符串中间的分隔符 */ ),)) )) as begin ) set @SourceSql=@SourceSql+@StrSeprate ...

  8. webstorm永久破解

    准备 1. webstorm下载 本次使用的是2017.3.3版本,如果找不到那么在此附上:webstorm各版本下载地址. 前段时间有朋友反馈破解不成功,今天本人亲测2017.3.3仍可以破解成功, ...

  9. 一起学Makefile(四)

    变量的定义 makefile中的变量,与C语言中的宏类似,它为一个文本字符串(变量的值,其类型只能是字符串类型)提供了一个名字(变量名). 变量的基本格式: 变量名   赋值符   变量值 变量名指的 ...

  10. vue-skeleton-webpack-plugin骨架屏与page-skeleton-webpack-plugin骨架屏生成插件

    vue-skeleton-webpack-plugin与page-skeleton-webpack-plugin使用 插件github地址:https://github.com/lavas-proje ...