读Secrets of the JavaScript Ninja对象

Posted secoding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读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." );

实例属性

  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对象的主要内容,如果未能解决你的问题,请参考以下文章

html 流畅的iframe没有javascript(来源:http://www.bymichaellancaster.com/blog/secrets-of-lea-verou-css)

ONLY中文怎么读

The monkey is ______ smart. 为啥写kind of 快点吧!亲们!

Read the ads中的ads为啥要加s?

JavaScrip book

好程序员分享JavaScrip数组去重操作实例小结