读Secrets of the JavaScript Ninja(二)对象
面向对象和原型
理解原型
在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." );
实例属性
- 当在原型和实例中有重名属性时,实例属性优先级比原型属性高
- 创建了多个实例,每个实例都是独立的拷贝,但是原型引用的是同一个方法
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(二)对象的更多相关文章
- 读Secrets of the JavaScript Ninja(一)函数
理解JavaScript为什么应该作为函数式 在JavaScript中,函数是程序执行过程中的主要模块单元 函数是第一类对象 通过字面量创建 function ninjaFunction(){} 赋值 ...
- [在读]Secrets of the javascript Ninja
很棒的一本,可惜没有中文版.
- 《Secrets of the JavaScript Ninja》:JavaScript 之运行时代码
最近,在阅读 jQuery 之父 John Resig 力作:Secrets of the JavaScript Ninja(JavaScript忍者秘籍).关于第九章提及的 JavaScript 之 ...
- 一、JavaScript概述 二、JavaScript的语法 三、JavaScript的内置对象
一.JavaScript的概述###<1>JavaScript的概念 又称ECMAScript,和java没有任何关系 嵌入在HTML元素中的 被浏览器解释运行的 一种脚本语言. ###& ...
- 二、JavaScript语言--JS基础--JavaScript进阶篇--JavaScript内置对象
1.什么事对象 JavaScript 中的所有事物都是对象,如:字符串.数值.数组.函数等,每个对象带有属性和方法. 对象的属性:反映该对象某些特定的性质的,如:字符串的长度.图像的长宽等: 对象的方 ...
- 2、JavaScript 基础二 (从零学习JavaScript)
11.强制转换 强制转换主要指使用Number.String和Boolean三个构造函数,手动将各种类型的值,转换成数字.字符串或者布尔值. 1>Number强制转换 参数为原始类型值的转换规 ...
- JavaScript三(对象思想)
JavaScript并不是面向对象的程序设计语言,但它是基于对象的.JavaScript中的每个函数都可用于创建对象,返回的对象既是该对象的实例,也是object的实例 . 一.对象与关联数组 Jav ...
- 学习javascript数据结构(二)——链表
前言 人生总是直向前行走,从不留下什么. 原文地址:学习javascript数据结构(二)--链表 博主博客地址:Damonare的个人博客 正文 链表简介 上一篇博客-学习javascript数据结 ...
- javascript中的对象,原型,原型链和面向对象
一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...
随机推荐
- 2019牛客暑期多校训练营(第八场)E:Explorer(LCT裸题 也可用线段树模拟并查集维护连通性)
题意:给定N,M,然后给出M组信息(u,v,l,r),表示u到v有[l,r]范围的通行证有效.问有多少种通行证可以使得1和N连通. 思路:和bzoj魔法森林有点像,LCT维护最小生成树. 开始和队友 ...
- 怎么避免写bug?
1:关注可能的业务逻辑异常:业务逻辑异常 可以通过各种输入输出 和 预期进行比较 即可很快发现. 2:关注可能的运行逻辑异常: 如 copy对象: 对象引用等 这类异常只看代码逻辑时很难发现的:代码写 ...
- 证明StringBuffer线程安全,StringBuilder线程不安全
证明StringBuffer线程安全,StringBuilder线程不安全证明StringBuffer线程安全StringBuilder线程不安全测试思想测试代码结果源码分析测试思想分别用1000个线 ...
- fitnesse管理引进的jar包
如下:需要引进的jar很多,并且路径都不一样,这样增加删减jar就比较麻烦 !*> setup!define TEST_SYSTEM {slim}!define LOCAL_PATH {C:\ ...
- Bzoj 4517: [Sdoi2016]排列计数(排列组合)
4517: [Sdoi2016]排列计数 Time Limit: 60 Sec Memory Limit: 128 MB Description 求有多少种长度为 n 的序列 A,满足以下条件: 1 ...
- 洛谷P2293 高精开根
锣鼓2293 写完了放代码 应该没什么思维难度 ———————————————————————————————————————————————————————— python真香 m=input() ...
- KVM原理及使用
Qemu 和 Qemu-kvm Qemu: http://qemu-project.org/Download Qemu-kvm:https://sourceforge.net/projects/kvm ...
- 系统权限远程线程注入到Explorer.exe
目录 提升为系统权限,注入到explorer中 一丶简介 二丶注入效果图 提升为系统权限,注入到explorer中 一丶简介 我们上一面说了系统服务拥有系统权限.并且拥有system权限.还尝试启动了 ...
- Oracle 的查询组合语句
select a.core_txn_srl_no||a.c_dept||a.c_batch||lpad(a.c_opr_no,5,'0')||case a.txn_dr_cr_ind when ' ...
- lintcode-828. 字模式
题目描述: 828.字模式 给定一个模式和一个字符串str,查找str是否遵循相同的模式.这里遵循的意思是一个完整的匹配,在一个字母的模式和一个非空的单词str之间有一个双向连接的模式对应. 样例 给 ...