From 447f8bb8f3656813500dbfccc7496377a6101cb3 Mon Sep 17 00:00:00 2001 From: Carol Date: Sun, 5 Aug 2018 21:20:38 +0800 Subject: [PATCH 1/2] translate complete 100% --- .../object-oriented-programming.json | 324 +++++++++--------- .../object-oriented-programming.md | 10 +- 2 files changed, 167 insertions(+), 167 deletions(-) diff --git a/02-javascript-algorithms-and-data-structures/object-oriented-programming.json b/02-javascript-algorithms-and-data-structures/object-oriented-programming.json index e55e814..4e2db8e 100644 --- a/02-javascript-algorithms-and-data-structures/object-oriented-programming.json +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.json @@ -675,17 +675,17 @@ "id": "587d7daf367417b2b2512b80", "title": "Remember to Set the Constructor Property when Changing the Prototype", "description": [ - "There is one crucial side effect of manually setting the prototype to a new object. It erased the constructor property! The code in the previous challenge would print the following for duck:", - "
console.log(duck.constructor)
// prints ‘undefined’ - Oops!
", - "To fix this, whenever a prototype is manually set to a new object, remember to define the constructor property:", - "
Bird.prototype = {
  constructor: Bird, // define the constructor property
  numLegs: 2,
  eat: function() {
    console.log(\"nom nom nom\");
  },
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", + "如果我们手动的给一个新对象重新设置原型的话,这将会产生一个重要的副作用:删除了constructor属性!所以在上一个挑战中,我们将duckconstructor属性输出到控制台的话将会得到以下结果:", + "
console.log(duck.constructor)
// 哎呀,控制台中输出了 ‘undefined’!
", + "为了解决这个问题,所以凡是原型被手动设置给了一个新对象,都要记得重新定义一个constructor属性:", + "
Bird.prototype = {
  constructor: Bird, // 定义 constructor 属性
  numLegs: 2,
  eat: function() {
    console.log(\"nom nom nom\");
  },
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", "
", - "Define the constructor property on the Dog prototype." + "给Dog 的原型定义一个constructor属性。" ], "tests": [ { - "text": "Dog.prototype should set the constructor property.", - "testString": "assert(Dog.prototype.constructor === Dog, 'Dog.prototype should set the constructor property.');" + "text": "Dog.prototype应该定义一个constructor属性。", + "testString": "assert(Dog.prototype.constructor === Dog, 'Dog.prototype应该定义一个constructor属性。');" } ], "solutions": [ @@ -704,7 +704,7 @@ " this.name = name; ", "}", "", - "// Modify the code below this line", + "// 请只修改这条注释以下的代码", "Dog.prototype = {", " ", " numLegs: 2, ", @@ -725,17 +725,17 @@ "id": "587d7db0367417b2b2512b81", "title": "Understand Where an Object’s Prototype Comes From", "description": [ - "Just like people inherit genes from their parents, an object inherits its prototype directly from the constructor function that created it. For example, here the Bird constructor creates the duck object:", + "就像人们从父母那里继承基因一样,对象也可直接从创建它的构造函数那里继承其原型。请看下面的例子:Bird构造函数创建了一个duck对象:", "
function Bird(name) {
  this.name = name;
}

let duck = new Bird(\"Donald\");
", - "duck inherits its prototype from the Bird constructor function. You can show this relationship with the isPrototypeOf method:", - "
Bird.prototype.isPrototypeOf(duck);
// returns true
", + "duck对象继承了Bird构造函数的原型。你可以使用isPrototypeOf方法来验证他们原型之间的关系:", + "
Bird.prototype.isPrototypeOf(duck);
// 返回 true
", "
", - "Use isPrototypeOf to check the prototype of beagle." + "使用isPrototypeOf方法验证beagle原型是否继承了Bird构造函数的原型。" ], "tests": [ { - "text": "Show that Dog.prototype is the prototype of beagle", - "testString": "assert(/Dog\\.prototype\\.isPrototypeOf\\(beagle\\)/.test(code), 'Show that Dog.prototype is the prototype of beagle');" + "text": "验证Dog.prototype应该是beagle原型。", + "testString": "assert(/Dog\\.prototype\\.isPrototypeOf\\(beagle\\)/.test(code), '验证Dog.prototype应该是beagle原型。');" } ], "solutions": [ @@ -756,7 +756,7 @@ "", "let beagle = new Dog(\"Snoopy\");", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "" ], @@ -769,22 +769,22 @@ "id": "587d7db0367417b2b2512b82", "title": "Understand the Prototype Chain", "description": [ - "All objects in JavaScript (with a few exceptions) have a prototype. Also, an object’s prototype itself is an object.", + "JavaScript 中所有的对象(除了少数例外)都有自己的原型。而且,对象的原型本身就是一个对象。", "
function Bird(name) {
  this.name = name;
}

typeof Bird.prototype; // => object
", - "Because a prototype is an object, a prototype can have its own prototype! In this case, the prototype of Bird.prototype is Object.prototype:", - "
Object.prototype.isPrototypeOf(Bird.prototype);
// returns true
", - "How is this useful? You may recall the hasOwnProperty method from a previous challenge:", + "正是因为原型也是一个对象,所以原型对象也有属于它自己的原型!这样看来的话,Bird.prototype原型就是Object.prototype:", + "
Object.prototype.isPrototypeOf(Bird.prototype);
// 返回 true
", + "这有什么作用呢?你可能还记得我们在上一个挑战中学到的hasOwnProperty方法:", "
let duck = new Bird(\"Donald\");
duck.hasOwnProperty(\"name\"); // => true
", - "The hasOwnProperty method is defined in Object.prototype, which can be accessed by Bird.prototype, which can then be accessed by duck. This is an example of the prototype chain.", - "In this prototype chain, Bird is the supertype for duck, while duck is the subtype. Object is a supertype for both Bird and duck.", - "Object is a supertype for all objects in JavaScript. Therefore, any object can use the hasOwnProperty method.", + "hasOwnProperty是定义在Object.prototype上的一个方法,Bird.prototypeduck对象方面并没有这个方法,但是我们可以在Bird.prototype上访问这个方法,还可以在duck对象上访问这个方法。这就是一个原型链。", + "在这个原型链中,Bird构造函数是duck实例的父级,那么duck就是子级Object则是Bird构造函数和duck实例共同的父级。", + "对象是 JavaScript 中所有对象的父级,也就是原型链的最顶层。因此,所有对象都可以访问hasOwnProperty这个方法。", "
", - "Modify the code to show the correct prototype chain." + "修改以下代码使其展示出正确的原型链。" ], "tests": [ { - "text": "Your code should show that Object.prototype is the prototype of Dog.prototype\")", - "testString": "assert(/Object\\.prototype\\.isPrototypeOf/.test(code), \"Your code should show that Object.prototype is the prototype of Dog.prototype\");" + "text": "你的代码应该展示Object.prototypeDog.prototype的原型。", + "testString": "assert(/Object\\.prototype\\.isPrototypeOf/.test(code), \"你的代码应该展示Object.prototypeDog.prototype的原型。\");" } ], "solutions": [ @@ -807,7 +807,7 @@ "", "Dog.prototype.isPrototypeOf(beagle); // => true", "", - "// Fix the code below so that it evaluates to true", + "// 修改以下代码使其结果返回 true", "???.isPrototypeOf(Dog.prototype);", "" ], @@ -820,28 +820,28 @@ "id": "587d7db0367417b2b2512b83", "title": "Use Inheritance So You Don't Repeat Yourself", "description": [ - "There's a principle in programming called Don't Repeat Yourself (DRY). The reason repeated code is a problem is because any change requires fixing code in multiple places. This usually means more work for programmers and more room for errors.", - "Notice in the example below that the describe method is shared by Bird and Dog:", + "编程中有一个潜在的原则就是:不要重复你的代码(简称:DRY )。编写重复的代码之所以会成为一个问题,是因为任何改变都需要去多个地方修复你所有重复的代码,这通常意味着我们需要做更多的工作,而且会产生更高的出错率。", + "请注意观察下面的示例,describe这个方法本应该是由BirdDog共享的:", "
Bird.prototype = {
  constructor: Bird,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};

Dog.prototype = {
  constructor: Dog,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", - "The describe method is repeated in two places. The code can be edited to follow the DRY principle by creating a supertype (or parent) called Animal:", + "但在上面的示例中,describe方法在两个地方重复定义了。根据上面所说的DRY原则,我们可以通过创建一个叫做Animal超类型(或者父类)来重写这段代码:", "
function Animal() { };

Animal.prototype = {
  constructor: Animal,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", - "Since Animal includes the describe method, you can remove it from Bird and Dog:", + "由于Animal构造函数包括了describe方法,所以你可以在BirdDog这两个构造函数里面去掉这个方法:", "
Bird.prototype = {
  constructor: Bird
};

Dog.prototype = {
  constructor: Dog
};
", "
", - "The eat method is repeated in both Cat and Bear. Edit the code in the spirit of DRY by moving the eat method to the Animal supertype." + "CatBear中的eat方法重复定义了。本着DRY的原则,通过将eat方法移动到Animal这个超类中来重写你的代码。" ], "tests": [ { - "text": "Animal.prototype should have the eat property.", - "testString": "assert(Animal.prototype.hasOwnProperty('eat'), 'Animal.prototype should have the eat property.');" + "text": "Animal.prototype应该有eat属性。", + "testString": "assert(Animal.prototype.hasOwnProperty('eat'), 'Animal.prototype应该有eat属性。');" }, { - "text": "Bear.prototype should not have the eat property.", - "testString": "assert(!(Bear.prototype.hasOwnProperty('eat')), 'Bear.prototype should not have the eat property.');" + "text": "Bear.prototype不应该有eat属性。", + "testString": "assert(!(Bear.prototype.hasOwnProperty('eat')), 'Bear.prototype不应该有eat属性。');" }, { - "text": "Cat.prototype should not have the eat property.", - "testString": "assert(!(Cat.prototype.hasOwnProperty('eat')), 'Cat.prototype should not have the eat property.');" + "text": "Cat.prototype不应该有eat属性。", + "testString": "assert(!(Cat.prototype.hasOwnProperty('eat')), 'Cat.prototype不应该有eat属性。');" } ], "solutions": [ @@ -894,35 +894,35 @@ "id": "587d7db0367417b2b2512b84", "title": "Inherit Behaviors from a Supertype", "description": [ - "In the previous challenge, you created a supertype called Animal that defined behaviors shared by all animals:", + "在上一个挑战中,我们创建了一个叫做Animal超类,用来定义所有动物共有的行为:", "
function Animal() { }
Animal.prototype.eat = function() {
  console.log(\"nom nom nom\");
};
", - "This and the next challenge will cover how to reuse Animal's methods inside Bird and Dog without defining them again. It uses a technique called inheritance.", - "This challenge covers the first step: make an instance of the supertype (or parent).", - "You already know one way to create an instance of Animal using the new operator:", + "在这一节以及下一节挑战中我们将涉及到如何将BirdDog中重写Animal的方法,而无需重新定义它们。这里我们将会用到构造函数里面的继承这个特性。", + "这一节挑战中我们学习第一步:创建一个超类(或者叫父类)的实例。", + "你已经学会了一种使用new操作符来创建一个Animal实例的方法:", "
let animal = new Animal();
", - "There are some disadvantages when using this syntax for inheritance, which are too complex for the scope of this challenge. Instead, here's an alternative approach without those disadvantages:", + "此语法用于继承时会存在一些缺点,这些缺点对于当前我们这个挑战的范围来说太负责了。相反,这里有一种没有这些缺点的方法来替代new操作:", "
let animal = Object.create(Animal.prototype);
", - "Object.create(obj) creates a new object, and sets obj as the new object's prototype. Recall that the prototype is like the \"recipe\" for creating an object. By setting the prototype of animal to be Animal's prototype, you are effectively giving the animal instance the same \"recipe\" as any other instance of Animal.", - "
animal.eat(); // prints \"nom nom nom\"
animal instanceof Animal; // => true
", + "Object.create(obj)创建了一个新对象,并指定了obj作为新对象的原型。回忆一下,我们之前就说过原型就像是创建对象的一个 \"配方\"。通过给animal原型设置为Animal构造函数的原型,你将可以有效的给animal对象以及Animal构造函数的任何其他实例相同的 \"配方\"。", + "
animal.eat(); // 输出 \"nom nom nom\"
animal instanceof Animal; // => true
", "
", - "Use Object.create to make two instances of Animal named duck and beagle." + "使用Object.create方法给Animal创建两个实例:duckbeagle。" ], "tests": [ { - "text": "The duck variable should be defined.", - "testString": "assert(typeof duck !== \"undefined\", 'The duck variable should be defined.');" + "text": "duck变量应该被定义为一个对象。", + "testString": "assert(typeof duck !== \"undefined\", 'duck变量应该被定义为一个对象。');" }, { - "text": "The beagle variable should be defined.", - "testString": "assert(typeof beagle !== \"undefined\", 'The beagle variable should be defined.');" + "text": "beagle变量应该被定义为一个对象。", + "testString": "assert(typeof beagle !== \"undefined\", 'The beagle变量应该被定义为一个对象。');" }, { - "text": "duck should have a prototype of Animal.", - "testString": "assert(duck instanceof Animal, 'duck should have a prototype of Animal.');" + "text": "duck的原型应该被设置为Animal构造函数的原型。", + "testString": "assert(duck instanceof Animal, 'duck的原型应该被设置为Animal构造函数的原型。');" }, { - "text": "beagle should have a prototype of Animal.", - "testString": "assert(beagle instanceof Animal, 'beagle should have a prototype of Animal.');" + "text": "beagle的原型应该被设置为Animal构造函数的原型。", + "testString": "assert(beagle instanceof Animal, 'beagle的原型应该被设置为Animal构造函数的原型。');" } ], "solutions": [ @@ -946,13 +946,13 @@ " }", "};", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", - "let duck; // Change this line", - "let beagle; // Change this line", + "let duck; // 修改这一行代码", + "let beagle; // 修改这一行代码", "", - "duck.eat(); // Should print \"nom nom nom\"", - "beagle.eat(); // Should print \"nom nom nom\" " + "duck.eat(); // 应该输出 \"nom nom nom\"", + "beagle.eat(); // 应该输出 \"nom nom nom\" " ], "head": [], "tail": [] @@ -963,19 +963,19 @@ "id": "587d7db1367417b2b2512b85", "title": "Set the Child's Prototype to an Instance of the Parent", "description": [ - "In the previous challenge you saw the first step for inheriting behavior from the supertype (or parent) Animal: making a new instance of Animal.", - "This challenge covers the next step: set the prototype of the subtype (or child)—in this case, Bird—to be an instance of Animal.", + "在上一个挑战中,我们学习了从超类 Animal(或者叫父类)继承其行为的第一个步骤:使用Object.create方法创建Animal的实例。", + "这一节挑战我们将学习第二个步骤:给子类型(或者子类)设置原型。这样一来,Bird就是Animal的一个实例了。", "
Bird.prototype = Object.create(Animal.prototype);
", - "Remember that the prototype is like the \"recipe\" for creating an object. In a way, the recipe for Bird now includes all the key \"ingredients\" from Animal.", - "
let duck = new Bird(\"Donald\");
duck.eat(); // prints \"nom nom nom\"
", - "duck inherits all of Animal's properties, including the eat method.", + "请记住,原型类似于创建对象的 \"配方\"。从某种意义上来说,现在Bird对象的配方包含了Animal构造函数的所有关键 \"成分\"。", + "
let duck = new Bird(\"Donald\");
duck.eat(); // 输出 \"nom nom nom\"
", + "duck继承了Animal构造函数的所有属性,也包括了eat方法。", "
", - "Modify the code so that instances of Dog inherit from Animal." + "修改你的代码,以实现Dog实例继承了Animal构造函数。" ], "tests": [ { - "text": "Dog.prototype should be an instance of Animal.", - "testString": "assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'Dog.prototype should be an instance of Animal.');" + "text": "Dog.prototype应该是Animal的一个实例。", + "testString": "assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'Dog.prototype应该是Animal的一个实例。');" } ], "solutions": [ @@ -1001,11 +1001,11 @@ "", "function Dog() { }", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "let beagle = new Dog();", - "beagle.eat(); // Should print \"nom nom nom\"" + "beagle.eat(); // 应该输出 \"nom nom nom\"" ], "head": [], "tail": [] @@ -1016,30 +1016,30 @@ "id": "587d7db1367417b2b2512b86", "title": "Reset an Inherited Constructor Property", "description": [ - "When an object inherits its prototype from another object, it also inherits the supertype's constructor property.", - "Here's an example:", + "当一个对象从另外一个对象那里继承了其原型,那么它也继承了父类的 constructor 属性。", + "请看下面的举例:", "
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
let duck = new Bird();
duck.constructor // function Animal(){...}
", - "But duck and all instances of Bird should show that they were constructed by Bird and not Animal. To do so, you can manually set Bird's constructor property to the Bird object:", + "但是duck和其他所有Bird的实例都应该表明它们是由Bird这个构造函数创建的,而不是由Animal创建的。为此,你可以手动的将Bird的 constructor 属性设置为Bird对象:", "
Bird.prototype.constructor = Bird;
duck.constructor // function Bird(){...}
", "
", - "Fix the code so duck.constructor and beagle.constructor return their respective constructors." + "修改你的代码,使得duck.constructorbeagle.constructor返回各自的 constructors 属性。" ], "tests": [ { - "text": "Bird.prototype should be an instance of Animal.", - "testString": "assert(Animal.prototype.isPrototypeOf(Bird.prototype), 'Bird.prototype should be an instance of Animal.');" + "text": "Bird.prototype应该是Animal的一个实例。", + "testString": "assert(Animal.prototype.isPrototypeOf(Bird.prototype), 'Bird.prototype应该是Animal的一个实例。');" }, { - "text": "duck.constructor should return Bird.", - "testString": "assert(duck.constructor === Bird, 'duck.constructor should return Bird.');" + "text": "duck.constructor应该返回Bird。", + "testString": "assert(duck.constructor === Bird, 'duck.constructor应该返回Bird。');" }, { - "text": "Dog.prototype should be an instance of Animal.", - "testString": "assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'Dog.prototype should be an instance of Animal.');" + "text": "Dog.prototype应该是Animal的一个实例。", + "testString": "assert(Animal.prototype.isPrototypeOf(Dog.prototype), 'Dog.prototype应该是Animal的一个实例。');" }, { - "text": "beagle.constructor should return Dog.", - "testString": "assert(beagle.constructor === Dog, 'beagle.constructor should return Dog.');" + "text": "beagle.constructor应该返回Dog。", + "testString": "assert(beagle.constructor === Dog, 'beagle.constructor应该返回Dog。');" } ], "solutions": [ @@ -1061,7 +1061,7 @@ "Bird.prototype = Object.create(Animal.prototype);", "Dog.prototype = Object.create(Animal.prototype);", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "", @@ -1077,36 +1077,36 @@ "id": "587d7db1367417b2b2512b87", "title": "Add Methods After Inheritance", "description": [ - "A constructor function that inherits its prototype object from a supertype constructor function can still have its own methods in addition to inherited methods.", - "For example, Bird is a constructor that inherits its prototype from Animal:", + "从父类构造函数继承其原型对象的构造函数除了继承过来的方法之外,还可以有自己的方法。", + "请看举例:Bird构造函数继承了Animal构造函数的原型:", "
function Animal() { }
Animal.prototype.eat = function() {
  console.log(\"nom nom nom\");
};
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;
", - "In addition to what is inherited from Animal, you want to add behavior that is unique to Bird objects. Here, Bird will get a fly() function. Functions are added to Bird's prototype the same way as any constructor function:", + "除了从Animal构造函数继承的行为之外,你可能还需要给Bird对象添加表示其唯一的行为。这里,我们给Bird对象添加一个fly()函数。函数以一种和其他任意构造函数相同的方式添加到Bird原型中:", "
Bird.prototype.fly = function() {
  console.log(\"I'm flying!\");
};
", - "Now instances of Bird will have both eat() and fly() methods:", - "
let duck = new Bird();
duck.eat(); // prints \"nom nom nom\"
duck.fly(); // prints \"I'm flying!\"
", + "现在Bird的实例中就有了eat()fly()这两个方法:", + "
let duck = new Bird();
duck.eat(); // 输出 \"nom nom nom\"
duck.fly(); // 输出 \"I'm flying!\"
", "
", - "Add all necessary code so the Dog object inherits from Animal and the Dog's prototype constructor is set to Dog. Then add a bark() method to the Dog object so that beagle can both eat() and bark(). The bark() method should print \"Woof!\" to the console." + "添加所有必要的代码,使得Dog对象继承Animal构造函数,并且把Dog 原型上的 constructor 属性设置为 Dog。然后给Dog对象添加一个bark()方法,这样的话,beagle将同时拥有eat()bark()这个两个方法。在bark()方法中应该将 \"Woof!\" 输出到控制台。" ], "tests": [ { - "text": "Animal should not respond to the bark() method.", - "testString": "assert(typeof Animal.prototype.bark == \"undefined\", 'Animal should not respond to the bark() method.');" + "text": "Animal应该不拥有bark()方法。", + "testString": "assert(typeof Animal.prototype.bark == \"undefined\", 'Animal应该不拥有bark()方法。');" }, { - "text": "Dog should inherit the eat() method from Animal.", - "testString": "assert(typeof Dog.prototype.eat == \"function\", 'Dog should inherit the eat() method from Animal.');" + "text": "Dog应该继承了Animal构造函数的eat()方法。", + "testString": "assert(typeof Dog.prototype.eat == \"function\", 'Dog应该继承了Animal构造函数的eat()方法。');" }, { - "text": "Dog should have the bark() method as an own property.", - "testString": "assert(Dog.prototype.hasOwnProperty('bark'), 'Dog should have the bark() method as an own property.');" + "text": "Dog应该有一个bark()方法作为自身属性。", + "testString": "assert(Dog.prototype.hasOwnProperty('bark'), 'Dog应该有一个bark()方法作为自身属性。');" }, { - "text": "beagle should be an instanceof Animal.", - "testString": "assert(beagle instanceof Animal, 'beagle should be an instanceof Animal.');" + "text": "beagle应该是Animal的一个instanceof。", + "testString": "assert(beagle instanceof Animal, 'beagle应该是Animal的一个instanceof。');" }, { - "text": "The constructor for beagle should be set to Dog.", - "testString": "assert(beagle.constructor === Dog, 'The constructor for beagle should be set to Dog.');" + "text": "beagle的 constructor 属性应该被设置为Dog。", + "testString": "assert(beagle.constructor === Dog, 'beagle的 constructor 属性应该被设置为Dog。');" } ], "solutions": [ @@ -1128,17 +1128,17 @@ "", "function Dog() { }", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下 ", "", "", "", "", - "// Add your code above this line", + "// 请把你的代码写在这条注释以下 ", "", "let beagle = new Dog();", "", - "beagle.eat(); // Should print \"nom nom nom\"", - "beagle.bark(); // Should print \"Woof!\"" + "beagle.eat(); // 应该输出 \"nom nom nom\"", + "beagle.bark(); // 应该输出 \"Woof!\"" ], "head": [], "tail": [] @@ -1149,29 +1149,29 @@ "id": "587d7db1367417b2b2512b88", "title": "Override Inherited Methods", "description": [ - "In previous lessons, you learned that an object can inherit its behavior (methods) from another object by cloning its prototype object:", + "在上一个挑战中,我们学习到了一个对象可以通过复制另一个对象的原型继承其属性和行为(或方法):", "
ChildObject.prototype = Object.create(ParentObject.prototype);
", - "Then the ChildObject received its own methods by chaining them onto its prototype:", + "然后,ChildObject通过将它们(即需要添加的方法)链接到它的原型中就可以访问到自己的方法了:", "
ChildObject.prototype.methodName = function() {...};
", - "It's possible to override an inherited method. It's done the same way - by adding a method to ChildObject.prototype using the same method name as the one to override.", - "Here's an example of Bird overriding the eat() method inherited from Animal:", - "
function Animal() { }
Animal.prototype.eat = function() {
  return \"nom nom nom\";
};
function Bird() { }

// Inherit all methods from Animal
Bird.prototype = Object.create(Animal.prototype);

// Bird.eat() overrides Animal.eat()
Bird.prototype.eat = function() {
  return \"peck peck peck\";
};
", - "If you have an instance let duck = new Bird(); and you call duck.eat(), this is how JavaScript looks for the method on duck’s prototype chain:", - "1. duck => Is eat() defined here? No.", - "2. Bird => Is eat() defined here? => Yes. Execute it and stop searching.", - "3. Animal => eat() is also defined, but JavaScript stopped searching before reaching this level.", - "4. Object => JavaScript stopped searching before reaching this level.", + "我们还可以重写继承的方法。还是以同样的方法,通过使用与要重写的方法相同的方法名向ChildObject.prototype中添加方法。", + "请看下面的举例:Bird重写了从Animal继承来的eat()方法:", + "
function Animal() { }
Animal.prototype.eat = function() {
  return \"nom nom nom\";
};
function Bird() { }

// 继承了 Animal 的所有方法
Bird.prototype = Object.create(Animal.prototype);

// Bird.eat() 重写了 Animal.eat() 方法
Bird.prototype.eat = function() {
  return \"peck peck peck\";
};
", + "如果你有一个实例:let duck = new Bird();,然后你调用了duck.eat(),这就是 JavaScript 如何在duck原型链上寻找方法:", + "1. duck => 这里定义了 eat() 方法吗?没有。", + "2. Bird => 这里定义了 eat() 方法吗?=> 是的。执行它并停止往上搜索。", + "3. Animal => 这里也定义了 eat() 方法,但是 JavaScript 在到达这层原型链之前已停止了搜索。", + "4. Object => JavaScript 在到达这层原型链之前也已经停止了搜索。", "
", - "Override the fly() method for Penguin so that it returns \"Alas, this is a flightless bird.\"" + "重写Penguin对象里面的fly()方法,使其返回 \"Alas, this is a flightless bird.\"" ], "tests": [ { - "text": "penguin.fly() should return the string \"Alas, this is a flightless bird.\"", - "testString": "assert(penguin.fly() === \"Alas, this is a flightless bird.\", 'penguin.fly() should return the string \"Alas, this is a flightless bird.\"');" + "text": "penguin.fly()方法应该返回字符串:\"Alas, this is a flightless bird.\"", + "testString": "assert(penguin.fly() === \"Alas, this is a flightless bird.\", 'penguin.fly()方法应该返回字符串:\"Alas, this is a flightless bird.\"');" }, { - "text": "The bird.fly() method should return \"I am flying!\"", - "testString": "assert((new Bird()).fly() === \"I am flying!\", 'The bird.fly() method should return \"I am flying!\"');" + "text": "The bird.fly()方法应该返回 \"I am flying!\"", + "testString": "assert((new Bird()).fly() === \"I am flying!\", 'The bird.fly()方法应该返回 \"I am flying!\"');" } ], "solutions": [ @@ -1194,11 +1194,11 @@ "Penguin.prototype = Object.create(Bird.prototype);", "Penguin.prototype.constructor = Penguin;", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "", - "// Add your code above this line", + "// 请把你的代码写在这条注释以下", "", "let penguin = new Penguin();", "console.log(penguin.fly());" @@ -1212,29 +1212,29 @@ "id": "587d7db2367417b2b2512b89", "title": "Use a Mixin to Add Common Behavior Between Unrelated Objects", "description": [ - "As you have seen, behavior is shared through inheritance. However, there are cases when inheritance is not the best solution. Inheritance does not work well for unrelated objects like Bird and Airplane. They can both fly, but a Bird is not a type of Airplane and vice versa.", - "For unrelated objects, it's better to use mixins. A mixin allows other objects to use a collection of functions.", + "正如你所见,行为是通过继承来共享的。然而,在有些情况下,继承不是最好的解决方案。继承不适用于那些不相关的对象,比如BirdAirplane。它们都可以飞行,但是一个Bird并不是一种Airplane,反之亦然。", + "对于不相关的对象,最好使用mixins类。一个mixin类允许其他对象使用函数集合。", "
let flyMixin = function(obj) {
  obj.fly = function() {
    console.log(\"Flying, wooosh!\");
  }
};
", - "The flyMixin takes any object and gives it the fly method.", + "flyMixin构造器能接受任何对象,并为其提供了fly方法。", "
let bird = {
  name: \"Donald\",
  numLegs: 2
};

let plane = {
  model: \"777\",
  numPassengers: 524
};

flyMixin(bird);
flyMixin(plane);
", - "Here bird and plane are passed into flyMixin, which then assigns the fly function to each object. Now bird and plane can both fly:", - "
bird.fly(); // prints \"Flying, wooosh!\"
plane.fly(); // prints \"Flying, wooosh!\"
", - "Note how the mixin allows for the same fly method to be reused by unrelated objects bird and plane.", + "这里,bird和code>plane
对象都被传递到了flyMixin,然后将fly方法分配给了每一个对象。现在birdplane都可以飞行了:", + "
bird.fly(); // 输出 \"Flying, wooosh!\"
plane.fly(); // 输出 \"Flying, wooosh!\"
", + "请注意:mixin是如何允许相同的fly方法被不相关的对象birdplane重用的。", "
", - "Create a mixin named glideMixin that defines a method named glide. Then use the glideMixin to give both bird and boat the ability to glide." + "创建一个名为glideMixinmixin类,并定义一个glide方法。然后使用glideMixin来给birdboat赋予滑行的能力。" ], "tests": [ { - "text": "Your code should declare a glideMixin variable that is a function.", - "testString": "assert(typeof glideMixin === \"function\", 'Your code should declare a glideMixin variable that is a function.');" + "text": "你的代码应该声明一个变量名为glideMixin的函数。", + "testString": "assert(typeof glideMixin === \"function\", '你的代码应该声明一个变量名为glideMixin的函数。');" }, { - "text": "Your code should use the glideMixin on the bird object to give it the glide method.", - "testString": "assert(typeof bird.glide === \"function\", 'Your code should use the glideMixin on the bird object to give it the glide method.');" + "text": "你的代码应该在bird上使用glideMixin,以提供glide方法。", + "testString": "assert(typeof bird.glide === \"function\", '你的代码应该在bird上使用glideMixin,以提供glide方法。');" }, { - "text": "Your code should use the glideMixin on the boat object to give it the glide method.", - "testString": "assert(typeof boat.glide === \"function\", 'Your code should use the glideMixin on the boat object to give it the glide method.');" + "text": "你的代码应该在boat上使用glideMixin,以提供glide方法。", + "testString": "assert(typeof boat.glide === \"function\", '你的代码应该在boat上使用glideMixin,以提供glide方法。');" } ], "solutions": [ @@ -1259,7 +1259,7 @@ " type: \"race-boat\"", "};", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "", @@ -1276,23 +1276,23 @@ "id": "587d7db2367417b2b2512b8a", "title": "Use Closure to Protect Properties Within an Object from Being Modified Externally", "description": [ - "In the previous challenge, bird had a public property name. It is considered public because it can be accessed and changed outside of bird's definition.", + "在上一次挑战中,bird有一个公共属性name。它之所以被认为是公共的,是因为它可以在bird的定义范围之外被访问和更改。", "
bird.name = \"Duffy\";
", - "Therefore, any part of your code can easily change the name of bird to any value. Think about things like passwords and bank accounts being easily changeable by any part of your codebase. That could cause a lot of issues.", - "The simplest way to make properties private is by creating a variable within the constructor function. This changes the scope of that variable to be within the constructor function versus available globally. This way, the property can only be accessed and changed by methods also within the constructor function.", - "
function Bird() {
  let hatchedEgg = 10; // private property

  this.getHatchedEggCount = function() { // publicly available method that a bird object can use
    return hatchedEgg;
  };
}
let ducky = new Bird();
ducky.getHatchedEggCount(); // returns 10
", - "Here getHachedEggCount is a privileged method, because it has access to the private variable hatchedEgg. This is possible because hatchedEgg is declared in the same context as getHachedEggCount. In JavaScript, a function always has access to the context in which it was created. This is called closure.", + "因此,你代码的任何部分都可以轻松地将bird的 name 属性更改为任意值。想想密码和银行账户之类的东西,如果你代码库的任何部分都可以轻易改变,那么将会引起很多问题。", + "使属性私有化最简单的方法就是通过在构造函数中创建变量。这改变了该变量在构造函数中的范围,而不是全局可用的范围。这样,属性只能由构造函数中的方法访问和更改。", + "
function Bird() {
  let hatchedEgg = 10; // 私有属性

  this.getHatchedEggCount = function() { // bird 对象可以是使用的公有方法
    return hatchedEgg;
  };
}
let ducky = new Bird();
ducky.getHatchedEggCount(); // 返回 10
", + "这里的getHachedEggCount是一种特权方法,因为它可以访问私有属性hatchedEgg。这是可能的,因为hatchedEgg是在与getHachedEggCount相同的上下文中声明的。在 JavaScript 中,函数总是可以访问创建它的上下文。这就叫做闭包。", "
", - "Change how weight is declared in the Bird function so it is a private variable. Then, create a method getWeight that returns the value of weight." + "更改在Bird函数中声明weight的方法,使其成为私有变量。然后,创建一个返回weight值的getWeight方法。" ], "tests": [ { - "text": "The weight property should be a private variable.", - "testString": "assert(!code.match(/this\\.weight/g), 'The weight property should be a private variable.');" + "text": "weight属性应该是一个私有变量。", + "testString": "assert(!code.match(/this\\.weight/g), 'The weight属性应该是一个私有变量。');" }, { - "text": "Your code should create a method in Bird called getWeight that returns the weight.", - "testString": "assert((new Bird()).getWeight() === 15, 'Your code should create a method in Bird called getWeight that returns the weight.');" + "text": "你的代码应该在Bird中创建一个名为getWeight方法,该方法返回weight值。", + "testString": "assert((new Bird()).getWeight() === 15, '你的代码应该在Bird中创建一个名为getWeight方法,该方法返回weight值。');" } ], "solutions": [ @@ -1323,20 +1323,20 @@ "id": "587d7db2367417b2b2512b8b", "title": "Understand the Immediately Invoked Function Expression (IIFE)", "description": [ - "A common pattern in JavaScript is to execute a function as soon as it is declared:", - "
(function () {
  console.log(\"Chirp, chirp!\");
})(); // this is an anonymous function expression that executes right away
// Outputs \"Chirp, chirp!\" immediately
", - "Note that the function has no name and is not stored in a variable. The two parentheses () at the end of the function expression cause it to be immediately executed or invoked. This pattern is known as an immediately invoked function expression or IIFE.", + "JavaScript 中的一个常见模式就是,函数一被声明就执行:", + "
(function () {
  console.log(\"Chirp, chirp!\");
})(); // 这是一个立即执行的匿名函数表达式
// 立即输出 \"Chirp, chirp!\"
", + "请注意,函数没有名称,也不存储在变量中。函数表达式末尾的两个括号()导致它被立即执行或调用。这种模式被叫做自执行函数表达式或者IIFE。", "
", - "Rewrite the function makeNest and remove its call so instead it's an anonymous immediately invoked function expression (IIFE)." + "重写函数makeNest,并删除它的调用,取而代之是一个匿名的自执行函数表达式IIFE)。" ], "tests": [ { - "text": "The function should be anonymous.", - "testString": "assert(/\\(\\s*?function\\s*?\\(\\s*?\\)\\s*?{/.test(code), 'The function should be anonymous.');" + "text": "该函数应该是匿名的。", + "testString": "assert(/\\(\\s*?function\\s*?\\(\\s*?\\)\\s*?{/.test(code), '该函数应该是匿名的。');" }, { - "text": "Your function should have parentheses at the end of the expression to call it immediately.", - "testString": "assert(/}\\s*?\\)\\s*?\\(\\s*?\\)/.test(code), 'Your function should have parentheses at the end of the expression to call it immediately.');" + "text": "你的函数应该在表达式的末尾有括号,以便立即调用它。", + "testString": "assert(/}\\s*?\\)\\s*?\\(\\s*?\\)/.test(code), '你的函数应该在表达式的末尾有括号,以便立即调用它。');" } ], "solutions": [ @@ -1366,28 +1366,28 @@ "id": "587d7db2367417b2b2512b8c", "title": "Use an IIFE to Create a Module", "description": [ - "An immediately invoked function expression (IIFE) is often used to group related functionality into a single object or module. For example, an earlier challenge defined two mixins:", + "一个自执行函数表达式IIFE)通常用于将相关功能分组到单个对象或者是模块中。例如,先前的挑战中定义了两种的一个混合类:", "
function glideMixin(obj) {
  obj.glide = function() {
    console.log(\"Gliding on the water\");
  };
}
function flyMixin(obj) {
  obj.fly = function() {
    console.log(\"Flying, wooosh!\");
  };
}
", - "We can group these mixins into a module as follows:", - "
let motionModule = (function () {
  return {
    glideMixin: function (obj) {
      obj.glide = function() {
        console.log(\"Gliding on the water\");
      };
    },
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log(\"Flying, wooosh!\");
      };
    }
  }
}) (); // The two parentheses cause the function to be immediately invoked
", - "Note that you have an immediately invoked function expression (IIFE) that returns an object motionModule. This returned object contains all of the mixin behaviors as properties of the object.", - "The advantage of the module pattern is that all of the motion behaviors can be packaged into a single object that can then be used by other parts of your code. Here is an example using it:", + "我们可以将这些mixins分成以下模块:", + "
let motionModule = (function () {
  return {
    glideMixin: function (obj) {
      obj.glide = function() {
        console.log(\"Gliding on the water\");
      };
    },
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log(\"Flying, wooosh!\");
      };
    }
  }
}) (); // 两个括号导致函数被立即调用
", + "请注意,你有一个自执行函数表达式IIFE)返回一个motionModule对象。这个返回的对象包含作为对象属性的所有mixin行为。", + "模块模式的优点是,所有的运动行为都可以打包成一个对象,然后由代码的其他部分使用。下面是一个使用它的例子:", "
motionModule.glideMixin(duck);
duck.glide();
", "
", - "Create a module named funModule to wrap the two mixins isCuteMixin and singMixin. funModule should return an object." + "创建一个名为funModule模块,将这两个mixinsisCuteMixinsingMixin包装起来。funModule应该返回一个对象。" ], "tests": [ { - "text": "funModule should be defined and return an object.", - "testString": "assert(typeof funModule === \"object\", 'funModule should be defined and return an object.');" + "text": "funModule应该被定义并返回一个对象。", + "testString": "assert(typeof funModule === \"object\", 'funModule应该被定义并返回一个对象。');" }, { - "text": "funModule.isCuteMixin should access a function.", - "testString": "assert(typeof funModule.isCuteMixin === \"function\", 'funModule.isCuteMixin should access a function.');" + "text": "funModule.isCuteMixin应该访问一个函数。", + "testString": "assert(typeof funModule.isCuteMixin === \"function\", 'funModule.isCuteMixin应该访问一个函数。');" }, { - "text": "funModule.singMixin should access a function.", - "testString": "assert(typeof funModule.singMixin === \"function\", 'funModule.singMixin should access a function.');" + "text": "funModule.singMixin应该访问一个函数。", + "testString": "assert(typeof funModule.singMixin === \"function\", 'funModule.singMixin应该访问一个函数。');" } ], "solutions": [ diff --git a/02-javascript-algorithms-and-data-structures/object-oriented-programming.md b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md index 4918604..1d4f7fa 100644 --- a/02-javascript-algorithms-and-data-structures/object-oriented-programming.md +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md @@ -1,9 +1,9 @@ -# Introduction to the Object Oriented Programming Challenges # +# 面向对象编程挑战简介 # -At its core, software development solves a problem or achieves a result with computation. The software development process first defines a problem, then presents a solution. Object oriented programming is one of several major approaches to the software development process. +软件开发的核心是通过计算解决问题或取得结果。软件开发过程首先定义问题,然后提出解决方案。面向对象编程是软件开发过程的几种主要方法之一。 -As its name implies, object oriented programming organizes code into object definitions. These are sometimes called classes, and they group together data with related behavior. The data is an object's attributes, and the behavior (or functions) are methods. +顾名思义,面向对象编程将代码组织成对象定义。这些有时被称为类,它们将数据和相关行为组合在一起。数据是对象的属性,行为(或函数)是方法。 -The object structure makes it flexible within a program. Objects can transfer information by calling and passing data to another object's methods. Also, new classes can receive, or inherit, all the features from a base or parent class. This helps to reduce repeated code. +对象结构使它在程序中变得灵活。对象可以通过调用数据并将数据传递给另一个对象的方法来传递信息。此外,新类可以从基类或父类接收或继承所有功能。这有助于减少重复代码。 -Your choice of programming approach depends on a few factors. These include the type of problem, as well as how you want to structure your data and algorithms. This section covers object oriented programming principles in JavaScript. +你对编程方法的选择取决于几个因素。这些包括问题的类型,以及如何构造数据和算法。本节将介绍 JavaScript 中面向对象的编程原则。 From af5bfe8f555af04bedcdcceedde8dd2fab8db9ff Mon Sep 17 00:00:00 2001 From: Carol <1428620591@qq.com> Date: Thu, 9 Aug 2018 16:23:13 +0800 Subject: [PATCH 2/2] modify --- .../object-oriented-programming.json | 126 +++++++++--------- .../object-oriented-programming.md | 6 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/02-javascript-algorithms-and-data-structures/object-oriented-programming.json b/02-javascript-algorithms-and-data-structures/object-oriented-programming.json index 4e2db8e..62e880f 100644 --- a/02-javascript-algorithms-and-data-structures/object-oriented-programming.json +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.json @@ -566,7 +566,7 @@ "description": [ "在上一个挑战中创建的实例对象duckbeagle都有一个特殊的constructor属性:", "
let duck = new Bird();
let beagle = new Dog();

console.log(duck.constructor === Bird); //输出 true
console.log(beagle.constructor === Dog); //输出 true
", - "需要注意到的是这个constructor属性是对创建这个实例的构造函数的一个引用。", + "需要注意的是这个constructor属性是对创建这个实例的构造函数的一个引用。", "constructor属性存在的一个优势是,我们可以通过检查这个属性来找出它是一个什么样的对象。下面是一个例子,来看看是怎么使用的:", "
function joinBirdFraternity(candidate) {
  if (candidate.constructor === Bird) {
    return true;
  } else {
    return false;
  }
}
", "注意:
由于constructor属性可以被重写(在下面两节挑战中将会遇到),所以使用instanceof方法来检查对象的类型会更好。", @@ -675,12 +675,12 @@ "id": "587d7daf367417b2b2512b80", "title": "Remember to Set the Constructor Property when Changing the Prototype", "description": [ - "如果我们手动的给一个新对象重新设置原型的话,这将会产生一个重要的副作用:删除了constructor属性!所以在上一个挑战中,我们将duckconstructor属性输出到控制台的话将会得到以下结果:", + "手动给新对象重新设置原型对象,会产生一个重要的副作用:删除了constructor属性!我们来看一下,上一个挑战中duckconstructor属性输出到控制台的结果:", "
console.log(duck.constructor)
// 哎呀,控制台中输出了 ‘undefined’!
", - "为了解决这个问题,所以凡是原型被手动设置给了一个新对象,都要记得重新定义一个constructor属性:", + "为了解决这个问题,凡是手动给新对象重新设置过原型对象的,都别忘记在原型对象中定义一个constructor属性:", "
Bird.prototype = {
  constructor: Bird, // 定义 constructor 属性
  numLegs: 2,
  eat: function() {
    console.log(\"nom nom nom\");
  },
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", "
", - "给Dog 的原型定义一个constructor属性。" + "给Dog 的原型对象定义一个constructor属性。" ], "tests": [ { @@ -725,12 +725,12 @@ "id": "587d7db0367417b2b2512b81", "title": "Understand Where an Object’s Prototype Comes From", "description": [ - "就像人们从父母那里继承基因一样,对象也可直接从创建它的构造函数那里继承其原型。请看下面的例子:Bird构造函数创建了一个duck对象:", + "就像人们从父母那里继承基因一样,对象也可直接从创建它的构造函数那里继承其prototype。请看下面的例子:Bird构造函数创建了一个duck对象:", "
function Bird(name) {
  this.name = name;
}

let duck = new Bird(\"Donald\");
", - "duck对象继承了Bird构造函数的原型。你可以使用isPrototypeOf方法来验证他们原型之间的关系:", + "duckBird构造函数那里继承了它的prototype,你可以使用isPrototypeOf方法来验证他们之间的关系:", "
Bird.prototype.isPrototypeOf(duck);
// 返回 true
", "
", - "使用isPrototypeOf方法验证beagle原型是否继承了Bird构造函数的原型。" + "使用isPrototypeOf方法验证beagle是否继承了Bird构造函数的prototype。" ], "tests": [ { @@ -769,15 +769,15 @@ "id": "587d7db0367417b2b2512b82", "title": "Understand the Prototype Chain", "description": [ - "JavaScript 中所有的对象(除了少数例外)都有自己的原型。而且,对象的原型本身就是一个对象。", + "JavaScript 中所有的对象(除了少数例外)都有自己的原型。而且,对象的原型本身也是一个对象。", "
function Bird(name) {
  this.name = name;
}

typeof Bird.prototype; // => object
", - "正是因为原型也是一个对象,所以原型对象也有属于它自己的原型!这样看来的话,Bird.prototype原型就是Object.prototype:", + "正因为原型是一个对象,所以原型对象也有它自己的原型!这样看来的话,Bird.prototype原型就是Object.prototype:", "
Object.prototype.isPrototypeOf(Bird.prototype);
// 返回 true
", "这有什么作用呢?你可能还记得我们在上一个挑战中学到的hasOwnProperty方法:", "
let duck = new Bird(\"Donald\");
duck.hasOwnProperty(\"name\"); // => true
", - "hasOwnProperty是定义在Object.prototype上的一个方法,Bird.prototypeduck对象方面并没有这个方法,但是我们可以在Bird.prototype上访问这个方法,还可以在duck对象上访问这个方法。这就是一个原型链。", - "在这个原型链中,Bird构造函数是duck实例的父级,那么duck就是子级Object则是Bird构造函数和duck实例共同的父级。", - "对象是 JavaScript 中所有对象的父级,也就是原型链的最顶层。因此,所有对象都可以访问hasOwnProperty这个方法。", + "hasOwnProperty是定义在Object.prototype上的一个方法,但是我们可以同时在Bird.prototypeduck对象上访问到这个方法,尽管这两个对象上并没有定义该方法。这就是一个原型链。", + "在这个原型链中,Bird构造函数是父级duck子级Object则是Bird构造函数和duck实例共同的父级。", + "Object是 JavaScript 中所有对象的父级,也就是原型链的最顶层。因此,所有对象都可以访问hasOwnProperty方法。", "
", "修改以下代码使其展示出正确的原型链。" ], @@ -820,15 +820,15 @@ "id": "587d7db0367417b2b2512b83", "title": "Use Inheritance So You Don't Repeat Yourself", "description": [ - "编程中有一个潜在的原则就是:不要重复你的代码(简称:DRY )。编写重复的代码之所以会成为一个问题,是因为任何改变都需要去多个地方修复你所有重复的代码,这通常意味着我们需要做更多的工作,而且会产生更高的出错率。", - "请注意观察下面的示例,describe这个方法本应该是由BirdDog共享的:", + "编程中有一条原则叫做:不要重复你自己(简称:DRY )。编写重复代码会产生的问题是:任何改变都需要去多个地方修复所有重复的代码。这通常意味着我们需要做更多的工作,会产生更高的出错率。", + "请观察下面的示例,BirdDog共享describe方法:", "
Bird.prototype = {
  constructor: Bird,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};

Dog.prototype = {
  constructor: Dog,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", - "但在上面的示例中,describe方法在两个地方重复定义了。根据上面所说的DRY原则,我们可以通过创建一个叫做Animal超类型(或者父类)来重写这段代码:", + "我们可以看到describe方法在两个地方重复定义了。根据以上所说的DRY原则,我们可以通过创建一个Animal 超类(或者父类)来重写这段代码:", "
function Animal() { };

Animal.prototype = {
  constructor: Animal,
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", - "由于Animal构造函数包括了describe方法,所以你可以在BirdDog这两个构造函数里面去掉这个方法:", + "Animal构造函数中定义了describe方法,可将BirdDog这两个构造函数的方法删除掉:", "
Bird.prototype = {
  constructor: Bird
};

Dog.prototype = {
  constructor: Dog
};
", "
", - "CatBear中的eat方法重复定义了。本着DRY的原则,通过将eat方法移动到Animal这个超类中来重写你的代码。" + "CatBear重复定义了eat方法。本着DRY的原则,通过将eat方法移动到Animal 超类中来重写你的代码。" ], "tests": [ { @@ -894,27 +894,27 @@ "id": "587d7db0367417b2b2512b84", "title": "Inherit Behaviors from a Supertype", "description": [ - "在上一个挑战中,我们创建了一个叫做Animal超类,用来定义所有动物共有的行为:", + "在上一个挑战中,我们创建了一个Animal 超类,用来定义所有动物共有的行为:", "
function Animal() { }
Animal.prototype.eat = function() {
  console.log(\"nom nom nom\");
};
", - "在这一节以及下一节挑战中我们将涉及到如何将BirdDog中重写Animal的方法,而无需重新定义它们。这里我们将会用到构造函数里面的继承这个特性。", + "在这一节以及下一节挑战中我们将学习如何给BirdDog重写Animal中的方法,而无需重新定义它们。这里我们会用到构造函数的继承特性。", "这一节挑战中我们学习第一步:创建一个超类(或者叫父类)的实例。", - "你已经学会了一种使用new操作符来创建一个Animal实例的方法:", + "你已经学会了一种创建Animal实例的方法,即使用new操作符:", "
let animal = new Animal();
", - "此语法用于继承时会存在一些缺点,这些缺点对于当前我们这个挑战的范围来说太负责了。相反,这里有一种没有这些缺点的方法来替代new操作:", + "此语法用于继承时会存在一些缺点,这些缺点对于当前我们这个挑战来说太复杂了。相反,我们学习另外一种没有这些缺点的方法来替代new操作:", "
let animal = Object.create(Animal.prototype);
", - "Object.create(obj)创建了一个新对象,并指定了obj作为新对象的原型。回忆一下,我们之前就说过原型就像是创建对象的一个 \"配方\"。通过给animal原型设置为Animal构造函数的原型,你将可以有效的给animal对象以及Animal构造函数的任何其他实例相同的 \"配方\"。", + "Object.create(obj)创建了一个新对象,并指定了obj作为新对象的原型。回忆一下,我们之前说过原型就像是创建对象的 \"配方\"。通过给animal原型设置为Animal构造函数的原型,就可以有效的给animal对象一个 \"配方\",与Animal的其他实例一样。", "
animal.eat(); // 输出 \"nom nom nom\"
animal instanceof Animal; // => true
", "
", "使用Object.create方法给Animal创建两个实例:duckbeagle。" ], "tests": [ { - "text": "duck变量应该被定义为一个对象。", - "testString": "assert(typeof duck !== \"undefined\", 'duck变量应该被定义为一个对象。');" + "text": "应该定义一个duck变量。", + "testString": "assert(typeof duck !== \"undefined\", '应该定义一个duck变量。');" }, { - "text": "beagle变量应该被定义为一个对象。", - "testString": "assert(typeof beagle !== \"undefined\", 'The beagle变量应该被定义为一个对象。');" + "text": "应该定义一个beagle变量。", + "testString": "assert(typeof beagle !== \"undefined\", '应该定义一个beagle变量。');" }, { "text": "duck的原型应该被设置为Animal构造函数的原型。", @@ -963,14 +963,14 @@ "id": "587d7db1367417b2b2512b85", "title": "Set the Child's Prototype to an Instance of the Parent", "description": [ - "在上一个挑战中,我们学习了从超类 Animal(或者叫父类)继承其行为的第一个步骤:使用Object.create方法创建Animal的实例。", + "在上一个挑战中,我们学习了从超类 Animal(或者叫父类)继承其行为的第一个步骤:创建一个Animal的实例。", "这一节挑战我们将学习第二个步骤:给子类型(或者子类)设置原型。这样一来,Bird就是Animal的一个实例了。", "
Bird.prototype = Object.create(Animal.prototype);
", - "请记住,原型类似于创建对象的 \"配方\"。从某种意义上来说,现在Bird对象的配方包含了Animal构造函数的所有关键 \"成分\"。", + "请记住,原型类似于创建对象的 \"配方\"。从某种意义上来说,Bird对象的配方包含了Animal构造函数的所有关键 \"成分\"。", "
let duck = new Bird(\"Donald\");
duck.eat(); // 输出 \"nom nom nom\"
", - "duck继承了Animal构造函数的所有属性,也包括了eat方法。", + "duck继承了Animal构造函数的所有属性,其中包括了eat方法。", "
", - "修改你的代码,以实现Dog实例继承了Animal构造函数。" + "修改你的代码,以实现Dog继承了Animal构造函数。" ], "tests": [ { @@ -1016,13 +1016,13 @@ "id": "587d7db1367417b2b2512b86", "title": "Reset an Inherited Constructor Property", "description": [ - "当一个对象从另外一个对象那里继承了其原型,那么它也继承了父类的 constructor 属性。", + "当一个对象从另一个对象那里继承了其原型,那它也继承了父类的 constructor 属性。", "请看下面的举例:", "
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
let duck = new Bird();
duck.constructor // function Animal(){...}
", - "但是duck和其他所有Bird的实例都应该表明它们是由Bird这个构造函数创建的,而不是由Animal创建的。为此,你可以手动的将Bird的 constructor 属性设置为Bird对象:", + "但是duck和其他所有Bird的实例都应该表明它们是由Bird创建的,而不是由Animal创建的。为此,你可以手动把Bird的 constructor 属性设置为Bird对象:", "
Bird.prototype.constructor = Bird;
duck.constructor // function Bird(){...}
", "
", - "修改你的代码,使得duck.constructorbeagle.constructor返回各自的 constructors 属性。" + "修改你的代码,使得duck.constructorbeagle.constructor返回各自的构造函数。" ], "tests": [ { @@ -1077,20 +1077,20 @@ "id": "587d7db1367417b2b2512b87", "title": "Add Methods After Inheritance", "description": [ - "从父类构造函数继承其原型对象的构造函数除了继承过来的方法之外,还可以有自己的方法。", - "请看举例:Bird构造函数继承了Animal构造函数的原型:", + "从父类继承其原型对象的构造函数除了继承的方法之外,还可以有自己的方法。", + "请看举例:Bird是一个构造函数,它继承了Animal构造函数的原型:", "
function Animal() { }
Animal.prototype.eat = function() {
  console.log(\"nom nom nom\");
};
function Bird() { }
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;
", - "除了从Animal构造函数继承的行为之外,你可能还需要给Bird对象添加表示其唯一的行为。这里,我们给Bird对象添加一个fly()函数。函数以一种和其他任意构造函数相同的方式添加到Bird原型中:", + "除了从Animal构造函数继承的行为之外,还需要给Bird对象添加能表示其唯一的行为。这里,我们给Bird对象添加一个fly()函数。函数会以一种与其他构造函数相同的方式添加到Bird原型中:", "
Bird.prototype.fly = function() {
  console.log(\"I'm flying!\");
};
", "现在Bird的实例中就有了eat()fly()这两个方法:", "
let duck = new Bird();
duck.eat(); // 输出 \"nom nom nom\"
duck.fly(); // 输出 \"I'm flying!\"
", "
", - "添加所有必要的代码,使得Dog对象继承Animal构造函数,并且把Dog 原型上的 constructor 属性设置为 Dog。然后给Dog对象添加一个bark()方法,这样的话,beagle将同时拥有eat()bark()这个两个方法。在bark()方法中应该将 \"Woof!\" 输出到控制台。" + "添加必要的代码,使得Dog对象继承Animal构造函数,并且把Dog 原型上的 constructor 属性设置为 Dog。然后给Dog对象添加一个bark()方法,这样的话,beagle将同时拥有eat()bark()这两个方法。bark()方法中应该输出 \"Woof!\" 到控制台。" ], "tests": [ { - "text": "Animal应该不拥有bark()方法。", - "testString": "assert(typeof Animal.prototype.bark == \"undefined\", 'Animal应该不拥有bark()方法。');" + "text": "Animal应该没有bark()方法。", + "testString": "assert(typeof Animal.prototype.bark == \"undefined\", 'Animal应该没有bark()方法。');" }, { "text": "Dog应该继承了Animal构造函数的eat()方法。", @@ -1149,20 +1149,20 @@ "id": "587d7db1367417b2b2512b88", "title": "Override Inherited Methods", "description": [ - "在上一个挑战中,我们学习到了一个对象可以通过复制另一个对象的原型继承其属性和行为(或方法):", + "在上一个挑战中,我们学习了一个对象可以通过复制另一个对象的原型来继承其属性和行为(或方法):", "
ChildObject.prototype = Object.create(ParentObject.prototype);
", - "然后,ChildObject通过将它们(即需要添加的方法)链接到它的原型中就可以访问到自己的方法了:", + "然后,ChildObject将自己的方法链接到它的原型中,这样就可以访问了:", "
ChildObject.prototype.methodName = function() {...};
", - "我们还可以重写继承的方法。还是以同样的方法,通过使用与要重写的方法相同的方法名向ChildObject.prototype中添加方法。", + "我们还可以重写继承的方法。以同样的方式——通过使用一个与需要重写的方法相同的方法名,向ChildObject.prototype中添加方法。", "请看下面的举例:Bird重写了从Animal继承来的eat()方法:", "
function Animal() { }
Animal.prototype.eat = function() {
  return \"nom nom nom\";
};
function Bird() { }

// 继承了 Animal 的所有方法
Bird.prototype = Object.create(Animal.prototype);

// Bird.eat() 重写了 Animal.eat() 方法
Bird.prototype.eat = function() {
  return \"peck peck peck\";
};
", - "如果你有一个实例:let duck = new Bird();,然后你调用了duck.eat(),这就是 JavaScript 如何在duck原型链上寻找方法:", + "如果你有一个实例:let duck = new Bird();,然后你调用了duck.eat(),以下就是 JavaScript 在duck原型链上寻找方法的过程:", "1. duck => 这里定义了 eat() 方法吗?没有。", "2. Bird => 这里定义了 eat() 方法吗?=> 是的。执行它并停止往上搜索。", "3. Animal => 这里也定义了 eat() 方法,但是 JavaScript 在到达这层原型链之前已停止了搜索。", "4. Object => JavaScript 在到达这层原型链之前也已经停止了搜索。", "
", - "重写Penguin对象里面的fly()方法,使其返回 \"Alas, this is a flightless bird.\"" + "重写Penguinfly()方法,使其返回 \"Alas, this is a flightless bird.\"" ], "tests": [ { @@ -1212,29 +1212,29 @@ "id": "587d7db2367417b2b2512b89", "title": "Use a Mixin to Add Common Behavior Between Unrelated Objects", "description": [ - "正如你所见,行为是通过继承来共享的。然而,在有些情况下,继承不是最好的解决方案。继承不适用于那些不相关的对象,比如BirdAirplane。它们都可以飞行,但是一个Bird并不是一种Airplane,反之亦然。", + "正如你所见,通过继承可以共享行为。然而,在有些情况下,继承不是最好的解决方案。它不适用于那些不相关的对象,比如BirdAirplane。虽然它们都可以飞行,但是一只Bird并不是一架Airplane,反之亦然。", "对于不相关的对象,最好使用mixins类。一个mixin类允许其他对象使用函数集合。", "
let flyMixin = function(obj) {
  obj.fly = function() {
    console.log(\"Flying, wooosh!\");
  }
};
", - "flyMixin构造器能接受任何对象,并为其提供了fly方法。", + "flyMixin构造器能接受任何对象,并为其提供fly方法。", "
let bird = {
  name: \"Donald\",
  numLegs: 2
};

let plane = {
  model: \"777\",
  numPassengers: 524
};

flyMixin(bird);
flyMixin(plane);
", - "这里,bird和code>plane
对象都被传递到了flyMixin,然后将fly方法分配给了每一个对象。现在birdplane都可以飞行了:", + "这里的flyMixin接收了bird和code>plane对象,然后将fly方法分配给了每一个对象。现在birdplane都可以飞行了:", "
bird.fly(); // 输出 \"Flying, wooosh!\"
plane.fly(); // 输出 \"Flying, wooosh!\"
", - "请注意:mixin是如何允许相同的fly方法被不相关的对象birdplane重用的。", + "注意观察mixin是如何允许相同的fly方法被不相关的对象birdplane重用的。", "
", "创建一个名为glideMixinmixin类,并定义一个glide方法。然后使用glideMixin来给birdboat赋予滑行的能力。" ], "tests": [ { - "text": "你的代码应该声明一个变量名为glideMixin的函数。", - "testString": "assert(typeof glideMixin === \"function\", '你的代码应该声明一个变量名为glideMixin的函数。');" + "text": "你应该声明一个变量名为glideMixin的函数。", + "testString": "assert(typeof glideMixin === \"function\", '你应该声明一个变量名为glideMixin的函数。');" }, { - "text": "你的代码应该在bird上使用glideMixin,以提供glide方法。", - "testString": "assert(typeof bird.glide === \"function\", '你的代码应该在bird上使用glideMixin,以提供glide方法。');" + "text": "你应该在bird上使用glideMixin,以提供glide方法。", + "testString": "assert(typeof bird.glide === \"function\", '你应该在bird上使用glideMixin,以提供glide方法。');" }, { - "text": "你的代码应该在boat上使用glideMixin,以提供glide方法。", - "testString": "assert(typeof boat.glide === \"function\", '你的代码应该在boat上使用glideMixin,以提供glide方法。');" + "text": "你应该在boat上使用glideMixin,以提供glide方法。", + "testString": "assert(typeof boat.glide === \"function\", '你应该在boat上使用glideMixin,以提供glide方法。');" } ], "solutions": [ @@ -1276,14 +1276,14 @@ "id": "587d7db2367417b2b2512b8a", "title": "Use Closure to Protect Properties Within an Object from Being Modified Externally", "description": [ - "在上一次挑战中,bird有一个公共属性name。它之所以被认为是公共的,是因为它可以在bird的定义范围之外被访问和更改。", + "在上一次挑战中,bird有一个公共属性name。公共属性的定义就是:它可以在bird的定义范围之外被访问和更改。", "
bird.name = \"Duffy\";
", - "因此,你代码的任何部分都可以轻松地将bird的 name 属性更改为任意值。想想密码和银行账户之类的东西,如果你代码库的任何部分都可以轻易改变,那么将会引起很多问题。", - "使属性私有化最简单的方法就是通过在构造函数中创建变量。这改变了该变量在构造函数中的范围,而不是全局可用的范围。这样,属性只能由构造函数中的方法访问和更改。", + "因此,代码的任何地方都可以轻松地将bird的 name 属性更改为任意值。想想密码和银行账户之类的东西,如果代码库的任何部分都可以轻易改变,那么将会引起很多问题。", + "使属性私有化最简单的方法就是在构造函数中创建变量。可以将该变量范围限定在构造函数中,而不是全局可用。这样,属性只能由构造函数中的方法访问和更改。", "
function Bird() {
  let hatchedEgg = 10; // 私有属性

  this.getHatchedEggCount = function() { // bird 对象可以是使用的公有方法
    return hatchedEgg;
  };
}
let ducky = new Bird();
ducky.getHatchedEggCount(); // 返回 10
", "这里的getHachedEggCount是一种特权方法,因为它可以访问私有属性hatchedEgg。这是可能的,因为hatchedEgg是在与getHachedEggCount相同的上下文中声明的。在 JavaScript 中,函数总是可以访问创建它的上下文。这就叫做闭包。", "
", - "更改在Bird函数中声明weight的方法,使其成为私有变量。然后,创建一个返回weight值的getWeight方法。" + "更改在Bird函数中声明的weight方法,使其成为私有变量。然后,创建一个返回weight值的getWeight方法。" ], "tests": [ { @@ -1335,8 +1335,8 @@ "testString": "assert(/\\(\\s*?function\\s*?\\(\\s*?\\)\\s*?{/.test(code), '该函数应该是匿名的。');" }, { - "text": "你的函数应该在表达式的末尾有括号,以便立即调用它。", - "testString": "assert(/}\\s*?\\)\\s*?\\(\\s*?\\)/.test(code), '你的函数应该在表达式的末尾有括号,以便立即调用它。');" + "text": "函数应该在表达式的末尾有括号,以便立即调用它。", + "testString": "assert(/}\\s*?\\)\\s*?\\(\\s*?\\)/.test(code), '函数应该在表达式的末尾有括号,以便立即调用它。');" } ], "solutions": [ @@ -1366,11 +1366,11 @@ "id": "587d7db2367417b2b2512b8c", "title": "Use an IIFE to Create a Module", "description": [ - "一个自执行函数表达式IIFE)通常用于将相关功能分组到单个对象或者是模块中。例如,先前的挑战中定义了两种的一个混合类:", + "一个自执行函数表达式IIFE)通常用于将相关功能分组到单个对象或者是模块中。例如,先前的挑战中定义了一个混合类:", "
function glideMixin(obj) {
  obj.glide = function() {
    console.log(\"Gliding on the water\");
  };
}
function flyMixin(obj) {
  obj.fly = function() {
    console.log(\"Flying, wooosh!\");
  };
}
", "我们可以将这些mixins分成以下模块:", - "
let motionModule = (function () {
  return {
    glideMixin: function (obj) {
      obj.glide = function() {
        console.log(\"Gliding on the water\");
      };
    },
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log(\"Flying, wooosh!\");
      };
    }
  }
}) (); // 两个括号导致函数被立即调用
", - "请注意,你有一个自执行函数表达式IIFE)返回一个motionModule对象。这个返回的对象包含作为对象属性的所有mixin行为。", + "
let motionModule = (function () {
  return {
    glideMixin: function (obj) {
      obj.glide = function() {
        console.log(\"Gliding on the water\");
      };
    },
    flyMixin: function(obj) {
      obj.fly = function() {
        console.log(\"Flying, wooosh!\");
      };
    }
  }
}) (); // 末尾的两个括号导致函数被立即调用
", + "注意:一个自执行函数表达式IIFE)返回了一个motionModule对象。返回的这个对象包含了作为对象属性的所有mixin行为。", "模块模式的优点是,所有的运动行为都可以打包成一个对象,然后由代码的其他部分使用。下面是一个使用它的例子:", "
motionModule.glideMixin(duck);
duck.glide();
", "
", diff --git a/02-javascript-algorithms-and-data-structures/object-oriented-programming.md b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md index 1d4f7fa..33bd5a8 100644 --- a/02-javascript-algorithms-and-data-structures/object-oriented-programming.md +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md @@ -1,9 +1,9 @@ # 面向对象编程挑战简介 # -软件开发的核心是通过计算解决问题或取得结果。软件开发过程首先定义问题,然后提出解决方案。面向对象编程是软件开发过程的几种主要方法之一。 +软件开发的核心是解决问题或通过计算获得结果。软件开发过程首先定义一个问题,然后提出一个解决方案。面向对象编程是软件开发过程的几种主要方法之一。 顾名思义,面向对象编程将代码组织成对象定义。这些有时被称为类,它们将数据和相关行为组合在一起。数据是对象的属性,行为(或函数)是方法。 -对象结构使它在程序中变得灵活。对象可以通过调用数据并将数据传递给另一个对象的方法来传递信息。此外,新类可以从基类或父类接收或继承所有功能。这有助于减少重复代码。 +对象结构能够在程序中灵活使用,比如对象可以通过调用数据并将数据传递给另一个对象的方法来传递信息。此外,新对象可以从基类(或父类)接收或继承所有功能,这有助于减少重复代码。 -你对编程方法的选择取决于几个因素。这些包括问题的类型,以及如何构造数据和算法。本节将介绍 JavaScript 中面向对象的编程原则。 +对于编程方法的选择取决于几个因素,其中包括问题的类型、如何构造数据以及算法等。本节将介绍 JavaScript 中面向对象的编程原则。