diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3715b4c --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Vim +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] +Session.vim + +# VSCode +.vscode/* +.vscode*.json + +# Jetbrains +.idea/ + +# Sublime +*.sublime-workspace + diff --git a/01-responsive-web-design/applied-accessibility.md b/01-responsive-web-design/applied-accessibility.md new file mode 100644 index 0000000..adf01d8 --- /dev/null +++ b/01-responsive-web-design/applied-accessibility.md @@ -0,0 +1,13 @@ +# Introduction to the Applied Accessibility Challenges # + +"Accessibility" generally means having web content and a user interface that can be understood, navigated, and interacted with by a broad audience. This includes people with visual, auditory, mobility, or cognitive disabilities. Websites should be open and accessible to everyone, regardless of a user's abilities or resources. Some users rely on assistive technology such as a screen reader or voice recognition software. Other users may be able to navigate through a site only using a keyboard. Keeping the needs of various users in mind when developing your project can go a long way towards creating an open web. Here are three general concepts this section will explore throughout the following challenges: + + +* have well-organized code that uses appropriate markup + +* ensure text alternatives exist for non-text and visual content + +* create an easily-navigated page that's keyboard-friendly + + +Having accessible web content is an ongoing challenge. A great resource for your projects going forward is the W3 Consortium's Web Content Accessibility Guidelines (WCAG). They set the international standard for accessibility and provide a number of criteria you can use to check your work. diff --git a/01-responsive-web-design/applied-visual-design.md b/01-responsive-web-design/applied-visual-design.md new file mode 100644 index 0000000..dce164c --- /dev/null +++ b/01-responsive-web-design/applied-visual-design.md @@ -0,0 +1,8 @@ +# Introduction to the Applied Visual Design Challenges # + +Visual Design in web development is a broad topic. It combines typography, color theory, graphics, animation, and page layout to help deliver a site's message. The definition of good design is a well-discussed subject, with many books on the theme. + +At a basic level, most web content provides a user with information. The visual design of the page can influence its presentation and a user's experience. In web development, HTML gives structure and semantics to a page's content, and CSS controls the layout and appearance of it. + +This section covers some of the basic tools developers use to create their own visual designs. + diff --git a/01-responsive-web-design/basic-css.json b/01-responsive-web-design/basic-css.json index ee7034d..e949b39 100644 --- a/01-responsive-web-design/basic-css.json +++ b/01-responsive-web-design/basic-css.json @@ -8,24 +8,24 @@ "id": "bad87fee1348bd9aedf08803", "title": "Change the Color of Text", "description": [ - "Now let's change the color of some of our text.", - "We can do this by changing the style of your h2 element.", - "The property that is responsible for the color of an element's text is the color style property.", - "Here's how you would set your h2 element's text color to blue:", + "现在来让我们修改一下文本的颜色。", + "我们通过修改h2元素里面的 style。", + "color属性可以控制文本元素颜色。", + "以下是改变h2元素为蓝色的方法:", "<h2 style=\"color: blue;\">CatPhotoApp</h2>", - "Note that it is a good practice to end inline style declarations with a ; .", + "请注意行内style最好以;来结束。", "
", - "Change your h2 element's style so that its text color is red." + "请把h2元素的文本颜色设置为红色。" ], "tests": [ { - "text": "Your h2 element should be red.", - "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", 'Your h2 element should be red.');" + "text": "你的h2元素应该为红色。", + "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", '你的h2元素应该为红色。');" }, { - "text": "Your style declaration should end with a ; .", - "testString": "assert(code.match(/\\s*CatPhotoApp\\s*<\\/h2>/),' Your style declaration should end with a ; .');" - } + "text": "h2元素的style 属性的值应该以;结束。", + "testString": "assert(code.match(/\\s*CatPhotoApp\\s*<\\/h2>/),'h2 元素 style 属性的值应该以 ; 结束。');" + ], "challengeType": 0, "files": { @@ -75,37 +75,33 @@ "id": "bad87fee1348bd9aedf08805", "title": "Use CSS Selectors to Style Elements", "description": [ - "With CSS, there are hundreds of CSS properties that you can use to change the way an element looks on your page.", - "When you entered <h2 style=\"color: red\">CatPhotoApp</h2>, you were styling that individual h2 element with inline CSS, which stands for Cascading Style Sheets.", - "That's one way to specify the style of an element, but there's a better way to apply CSS.", - "At the top of your code, create a style block like this:", + "在CSS中,有上百种属性可以让你改变页面样式。", + "通过输入 <h2 style=\"color: red\">CatPhotoApp</h2>行内样式,修改单一的h2元素的颜色的方式,配置 层叠样式表(CSS) 的方式之一。", + "这是改变元素样式的一个特别方法,不过存在着更好的方法来设置层叠样式表(CSS。", + "在代码的顶部,创建一个 style 声明区域,如下方所示:", "
<style>
</style>
", - "Inside that style block, you can create a CSS selector for all h2 elements. For example, if you wanted all h2 elements to be red, you would add a style rule that looks like this:", + "在style样式声明区域内,可以创建一个CSS 选择器的规则来应用于所有的h2元素。例如,如果你想所有h2元素变成红色,可以添加下方的样式规则:", "
<style>
  h2 {color: red;}
</style>
", - "Note that it's important to have both opening and closing curly braces ({ and }) around each element's style rule(s). You also need to make sure that your element's style definition is between the opening and closing style tags. Finally, be sure to add a semicolon to the end of each of your element's style rules.", + "注意,在每个元素的样式声明区域里,左右花括号({})一定要写全。你需要确定你定义的样式规则位于花括号之间。以及,记得在每个元素样式规则的末尾添加分号。", "
", - "Delete your h2 element's style attribute, and instead create a CSS style block. Add the necessary CSS to turn all h2 elements blue." + "删除h2元素的行内样式,创建style样式声明区域。添加CSS样式规则使h2元素变为蓝色。" ], "tests": [ { - "text": "Remove the style attribute from your h2 element.", - "testString": "assert(!$(\"h2\").attr(\"style\"), 'Remove the style attribute from your h2 element.');" - }, - { - "text": "Create a style element.", - "testString": "assert($(\"style\") && $(\"style\").length > 1, 'Create a style element.');" + "text": "移除h2元素的行内样式。", + "testString": "assert(!$(\"h2\").attr(\"style\"), '移除h2元素的行内样式。');" }, { - "text": "Your h2 element should be blue.", - "testString": "assert($(\"h2\").css(\"color\") === \"rgb(0, 0, 255)\", 'Your h2 element should be blue.');" + "text": "创建一个style样式声明区域。", + "testString": "assert($(\"style\") && $(\"style\").length > 1, '创建一个style样式声明区域。');" }, { - "text": "Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace.", - "testString": "assert(code.match(/h2\\s*\\{\\s*color\\s*:.*;\\s*\\}/g), 'Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace.');" + "text": "h2元素颜色应为蓝色。", + "testString": "assert($(\"h2\").css(\"color\") === \"rgb(0, 0, 255)\", 'h2元素颜色应为蓝色。');" }, { - "text": "Make sure all your style elements are valid and have a closing tag.", - "testString": "assert(code.match(/<\\/style>/g) && code.match(/<\\/style>/g).length === (code.match(//g) || []).length, 'Make sure all your style elements are valid and have a closing tag.');" + "text": "确保你的样式声明里的h2规则需以花括号所包括,和分号结束。", + "testString": "assert(code.match(/h2\\s*\\{\\s*color\\s*:.*;\\s*\\}/g), '确保你的样式声明里的h2规则需以花括号所包括,和分号结束。');" } ], "challengeType": 0, @@ -156,33 +152,33 @@ "id": "bad87fee1348bd9aecf08806", "title": "Use a CSS Class to Style an Element", "description": [ - "Classes are reusable styles that can be added to HTML elements.", - "Here's an example CSS class declaration:", + "CSS 的class具有可重用性,可应用于各种 HTML 元素。", + "一个 CSSclass声明示例,如下所示:", "
<style>
  .blue-text {
    color: blue;
  }
</style>
", - "You can see that we've created a CSS class called blue-text within the <style> tag.", - "You can apply a class to an HTML element like this:", + "可以看到,我们在<style>样式声明区域里,创建了一个名为blue-textclass选择器。", + "你可以将 CSSclass选择器应用到一个HTML元素里,如下所示:", "<h2 class=\"blue-text\">CatPhotoApp</h2>", - "Note that in your CSS style element, class names start with a period. In your HTML elements' class attribute, the class name does not include the period.", + "注意你的style样式区域声明里,class需以句号开头。而在你的HTML元素里的class属性的类名,不需要包含句号", "
", - "Inside your style element, change the h2 selector to .red-text and update the color's value from blue to red.", - "Give your h2 element the class attribute with a value of 'red-text'." + "在style样式声明里,h2元素选择器改为.red-text的 CSS class 择器,同时将颜色blue变为red。", + "在你的h2元素里,添加一个class属性,且值为'red-text'。" ], "tests": [ { - "text": "Your h2 element should be red.", - "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", 'Your h2 element should be red.');" + "text": "你的h2元素应该为红色。", + "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", '你的h2元素应该为红色。');" }, { - "text": "Your h2 element should have the class red-text.", - "testString": "assert($(\"h2\").hasClass(\"red-text\"), 'Your h2 element should have the class red-text.');" + "text": "你的h2元素应含有red-text class 选择器。", + "testString": "assert($(\"h2\").hasClass(\"red-text\"), '你的h2元素应含有red-text class 选择器。');" }, { - "text": "Your stylesheet should declare a red-text class and have its color set to red.", - "testString": "assert(code.match(/\\.red-text\\s*\\{\\s*color\\s*:\\s*red;\\s*\\}/g), 'Your stylesheet should declare a red-text class and have its color set to red.');" + "text": "你的style样式声明区域里应该包含一个red-text class 选择器,并且它的颜色应为红色。", + "testString": "assert(code.match(/\\.red-text\\s*\\{\\s*color\\s*:\\s*red;\\s*\\}/g), '你的style样式声明区域里应该包含一个red-text class 选择器,并且它的颜色应为红色。');" }, { - "text": "Do not use inline style declarations like style=\"color: red\" in your h2 element.", - "testString": "assert($(\"h2\").attr(\"style\") === undefined, 'Do not use inline style declarations like style=\"color: red\" in your h2 element.');" + "text": "不要在h2元素里使用style=\"color: red\"的行内样式 。", + "testString": "assert($(\"h2\").attr(\"style\") === undefined, '不要在h2元素里使用style=\"color: red\"的行内样式 。');" } ], "challengeType": 0, @@ -239,28 +235,28 @@ "id": "bad87fee1348bd9aefe08806", "title": "Style Multiple Elements with a CSS Class", "description": [ - "Classes allow you to use the same CSS styles on multiple HTML elements. You can see this by applying your red-text class to the first p element." + "通过 CSS class 选择器,多个 HTML 元素可以使用相同的 CSS 样式规则。你可以将red-text class 选择器应用在第一个p元素上。" ], "tests": [ { - "text": "Your h2 element should be red.", - "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", 'Your h2 element should be red.');" + "text": "你的h2元素应该是红色的。", + "testString": "assert($(\"h2\").css(\"color\") === \"rgb(255, 0, 0)\", '你的h2元素应该是红色的。');" }, { - "text": "Your h2 element should have the class red-text.", - "testString": "assert($(\"h2\").hasClass(\"red-text\"), 'Your h2 element should have the class red-text.');" + "text": "你的h2元素应该含有名为red-text 的 class 选择器。", + "testString": "assert($(\"h2\").hasClass(\"red-text\"), '你的h2元素应该含有名为red-text 的 class 选择器。');" }, { - "text": "Your first p element should be red.", - "testString": "assert($(\"p:eq(0)\").css(\"color\") === \"rgb(255, 0, 0)\", 'Your first p element should be red.');" + "text": "你的第一个p元素应该为红色。", + "testString": "assert($(\"p:eq(0)\").css(\"color\") === \"rgb(255, 0, 0)\", '你的第一个p元素应该为红色。');" }, { - "text": "Your second and third p elements should not be red.", - "testString": "assert(!($(\"p:eq(1)\").css(\"color\") === \"rgb(255, 0, 0)\") && !($(\"p:eq(2)\").css(\"color\") === \"rgb(255, 0, 0)\"), 'Your second and third p elements should not be red.');" + "text": "你的第二和第三个p元素不应该为红色。", + "testString": "assert(!($(\"p:eq(1)\").css(\"color\") === \"rgb(255, 0, 0)\") && !($(\"p:eq(2)\").css(\"color\") === \"rgb(255, 0, 0)\"), '你的第二和第三个p元素不应该为红色。');" }, { - "text": "Your first p element should have the class red-text.", - "testString": "assert($(\"p:eq(0)\").hasClass(\"red-text\"), 'Your first p element should have the class red-text.');" + "text": "你的第一个p元素应该包含名为red-text的 class 选择器。", + "testString": "assert($(\"p:eq(0)\").hasClass(\"red-text\"), '你的第一个p 元素应该包含名为red-text的 class 选择器。');" } ], "challengeType": 0, @@ -317,15 +313,15 @@ "id": "bad87fee1348bd9aedf08806", "title": "Change the Font Size of an Element", "description": [ - "Font size is controlled by the font-size CSS property, like this:", + "字体大小由font-size的 CSS 属性控制,如下所示:", "
h1 {
  font-size: 30px;
}
", "
", - "Inside the same <style> tag that contains your red-text class, create an entry for p elements and set the font-size to 16 pixels (16px)." + "在包含red-text class 的<style>声明区域的里,创建一个p元素样式规则,并设置font-size为 16 像素(16px)。" ], "tests": [ { - "text": "Between the style tags, give the p elements font-size of 16px. Browser and Text zoom should be at 100%.", - "testString": "assert(code.match(/p\\s*{\\s*font-size\\s*:\\s*16\\s*px\\s*;\\s*}/i), 'Between the style tags, give the p elements font-size of 16px. Browser and Text zoom should be at 100%.');" + "text": "在style样式声明区域里,p元素的font-size的值应为16px,浏览器和文本缩放应设置为 100%。", + "testString": "assert(code.match(/p\\s*{\\s*font-size\\s*:\\s*16\\s*px\\s*;\\s*}/i), '在style样式声明区域里,p元素的font-size的值应为16px,浏览器和文本缩放应设置为 100%。');" } ], "challengeType": 0, @@ -382,16 +378,16 @@ "id": "bad87fee1348bd9aede08807", "title": "Set the Font Family of an Element", "description": [ - "You can set which font an element should use, by using the font-family property.", - "For example, if you wanted to set your h2 element's font to sans-serif, you would use the following CSS:", + "通过font-family属性,可以设置元素里面的字体样式。", + "例如,如果你想设置h2元素的字体为sans-serif,你可以用以下的 CSS 规则:", "
h2 {
  font-family: sans-serif;
}
", "
", - "Make all of your p elements use the monospace font." + "确保你所有的p元素使用monospace字体。" ], "tests": [ { - "text": "Your p elements should use the font monospace.", - "testString": "assert($(\"p\").not(\".red-text\").css(\"font-family\").match(/monospace/i), 'Your p elements should use the font monospace.');" + "text": "你的p元素应该使用monospace字体。", + "testString": "assert($(\"p\").not(\".red-text\").css(\"font-family\").match(/monospace/i), '你的p元素应该使用monospace字体。');" } ], "challengeType": 0, @@ -4399,4 +4395,4 @@ } } ] -} \ No newline at end of file +} diff --git a/01-responsive-web-design/basic-css.md b/01-responsive-web-design/basic-css.md new file mode 100644 index 0000000..c3c039c --- /dev/null +++ b/01-responsive-web-design/basic-css.md @@ -0,0 +1,18 @@ +# Introduction to Basic CSS # + +Cascading Style Sheets (CSS) tell the browser how to display the text and other content that you write in HTML. + +Note that CSS is case-sensitive so be careful with your capitalization. CSS has been adopted by all major browsers and allows you to control: + +* color +* fonts +* positioning +* spacing +* sizing +* decorations +* transitions + +There are three main ways to apply CSS styling. You can apply inline styles directly to HTML elements with the `style` attribute. Alternatively, you can place CSS rules within `style` tags in an HTML document. Finally, you can write CSS rules in an external style sheet, then reference that file in the HTML document. Even though the first two options have their use cases, most developers prefer external style sheets because they keep the styles separate from the HTML elements. This improves the readability and reusability of your code. The idea behind CSS is that you can use a selector to target an HTML element in the DOM (Document Object Model) and then apply a variety of attributes to that element to change the way it is displayed on the page. + +In this section, you'll see how adding CSS styles to the elements of your CatPhotoApp can change it from simple text to something more. + diff --git a/01-responsive-web-design/basic-html-and-html5.json b/01-responsive-web-design/basic-html-and-html5.json index 7f00e0b..3df7a2a 100644 --- a/01-responsive-web-design/basic-html-and-html5.json +++ b/01-responsive-web-design/basic-html-and-html5.json @@ -8,23 +8,21 @@ "id": "bd7123c8c441eddfaeb5bdef", "title": "Say Hello to HTML Elements", "description": [ - "Welcome to freeCodeCamp's HTML coding challenges. These will walk you through web development step-by-step.", - "First, you'll start by building a simple web page using HTML. You can edit code in your code editor, which is embedded into this web page.", - "Do you see the code in your code editor that says <h1>Hello</h1>? That's an HTML element.", - "Most HTML elements have an opening tag and a closing tag.", - "Opening tags look like this:", - "<h1>", - "Closing tags look like this:", - "</h1>", - "The only difference between opening and closing tags is the forward slash after the opening bracket of a closing tag.", - "Each challenge has tests you can run at any time by clicking the \"Run tests\" button. When you pass all tests, you'll be prompted to submit your solution and go to the next coding challenge.", + "欢迎来到 freeCodeCamp 的 HTML 编码挑战,这些挑战将会帮助你逐步掌握 Web 开发。", + "HTML 是英文 Hyper Text Markup Language(超文本标记语言)的缩写。首先,使用 HTML 来制作一个简单的网页,你可以直接在本网页内置的代码编辑器中编辑代码。", + "你看到代码编辑器中的 <h1>Hello</h1> 了吗? 那就是一个 HTML 标签。", + "大部分 HTML 标签都有一个 开始标记 和一个 结束标记。", + "开始标记像这样:<h1>", + "结束标记像这样:</h1>", + "开始标记和结束标记的唯一区别就是结束标记多了一个 /。", + "每个挑战都有测试,任何时候点击运行测试按钮就可以运行测试。如果代码通过测试,将会弹出一个窗口,你就可以提交你的代码并顺利进入下一个挑战。", "
", - "To pass the test on this challenge, change your h1 element's text to say \"Hello World\"." + "请把 h1 标签的内容改为:Hello World。" ], "tests": [ { - "text": "Your h1 element should have the text \"Hello World\".", - "testString": "assert.isTrue((/hello(\\s)+world/gi).test($('h1').text()), 'Your h1 element should have the text \"Hello World\".');" + "text": "h1 标签的内容应该为:Hello World。", + "testString": "assert.isTrue((/hello(\\s)+world/gi).test($('h1').text()), 'h1 标签的内容应该为:Hello World。');" } ], "challengeType": 0, @@ -45,28 +43,28 @@ "id": "bad87fee1348bd9aedf0887a", "title": "Headline with the h2 Element", "description": [ - "Over the next few lessons, we'll build an HTML5 cat photo web app piece-by-piece.", - "The h2 element you will be adding in this step will add a level two heading to the web page.", - "This element tells the browser about the structure of your website. h1 elements are often used for main headings, while h2 elements are generally used for subheadings. There are also h3, h4, h5 and h6 elements to indicate different levels of subheadings.", + "在接下来的几节课里,我们将会由浅入深地制作一个关于猫的图片应用。", + "这节课将会引入 h2 标签。", + "这些标签用来告诉浏览器,网站的结构长什么样子。h1 标签通常被用作主标题,h2 标签通常被用作副标题,还有 h3h4h5h6 标签,它们分别用作不同级别的标题。", "
", - "Add an h2 tag that says \"CatPhotoApp\" to create a second HTML element below your \"Hello World\" h1 element." + "在 h1 标签下面创建一个 h2 标签,标签内容为:CatPhotoApp。" ], "tests": [ { - "text": "Create an h2 element.", - "testString": "assert(($(\"h2\").length > 0), 'Create an h2 element.');" + "text": "创建一个 h2 标签。", + "testString": "assert(($(\"h2\").length > 0), '创建一个 h2 标签。');" }, { - "text": "Make sure your h2 element has a closing tag.", - "testString": "assert(code.match(/<\\/h2>/g) && code.match(/<\\/h2>/g).length === code.match(/

/g).length, 'Make sure your h2 element has a closing tag.');" + "text": "h2 标签应该有结束标记。", + "testString": "assert(code.match(/<\\/h2>/g) && code.match(/<\\/h2>/g).length === code.match(/

/g).length, 'h2 标签应该有结束标记。');" }, { - "text": "Your h2 element should have the text \"CatPhotoApp\".", - "testString": "assert.isTrue((/cat(\\s)?photo(\\s)?app/gi).test($(\"h2\").text()), 'Your h2 element should have the text \"CatPhotoApp\".');" + "text": "h2 标签的内容应该为:CatPhotoApp。", + "testString": "assert.isTrue((/cat(\\s)?photo(\\s)?app/gi).test($(\"h2\").text()), 'h2 标签的内容应该为:CatPhotoApp。');" }, { - "text": "Your h1 element should have the text \"Hello World\".", - "testString": "assert.isTrue((/hello(\\s)+world/gi).test($(\"h1\").text()), 'Your h1 element should have the text \"Hello World\".');" + "text": "h1 标签的内容应该为:Hello World。", + "testString": "assert.isTrue((/hello(\\s)+world/gi).test($(\"h1\").text()), '主标题的内容应该为:Hello World。');" } ], "challengeType": 0, @@ -87,24 +85,24 @@ "id": "bad87fee1348bd9aedf08801", "title": "Inform with the Paragraph Element", "description": [ - "p elements are the preferred element for paragraph text on websites. p is short for \"paragraph\".", - "You can create a paragraph element like this:", + "pparagraph 的缩写,通常被用来创建一个段落,就和你写作文一样。", + "你可以像这样创建一个段落:", "<p>I'm a p tag!</p>", "
", - "Create a p element below your h2 element, and give it the text \"Hello Paragraph\"." + "在 h2 标签下面新增一个 p 标签,标签内容是:Hello Paragraph。" ], "tests": [ { - "text": "Create a p element.", - "testString": "assert(($(\"p\").length > 0), 'Create a p element.');" + "text": "创建一个 p 标签。", + "testString": "assert(($(\"p\").length > 0), '创建一个 p 标签。');" }, { - "text": "Your p element should have the text \"Hello Paragraph\".", - "testString": "assert.isTrue((/hello(\\s)+paragraph/gi).test($(\"p\").text()), 'Your p element should have the text \"Hello Paragraph\".');" + "text": "p 标签的内容应该为:Hello Paragraph。", + "testString": "assert.isTrue((/hello(\\s)+paragraph/gi).test($(\"p\").text()), 'p 标签的内容应该为:Hello Paragraph。');" }, { - "text": "Make sure your p element has a closing tag.", - "testString": "assert(code.match(/<\\/p>/g) && code.match(/<\\/p>/g).length === code.match(/

p element has a closing tag.');" + "text": "p 标签应该有结束标记。", + "testString": "assert(code.match(/<\\/p>/g) && code.match(/<\\/p>/g).length === code.match(/

p 标签应该有结束标记。');" } ], "challengeType": 0, @@ -126,16 +124,16 @@ "id": "bad87fee1348bd9aedf08833", "title": "Fill in the Blank with Placeholder Text", "description": [ - "Web developers traditionally use lorem ipsum text as placeholder text. The 'lorem ipsum' text is randomly scraped from a famous passage by Cicero of Ancient Rome.", - "Lorem ipsum text has been used as placeholder text by typesetters since the 16th century, and this tradition continues on the web.", - "Well, 5 centuries is long enough. Since we're building a CatPhotoApp, let's use something called kitty ipsum text.", + "Web 开发者通常用 lorem ipsum text 来做占位符,占位符就是占着位置的一些文字,没有实际意义。", + "为什么叫 lorem ipsum text 呢?是因为 lorem ipsum 是古罗马西塞罗谚语的前两个单词。", + "从公元16世纪开始 lorem ipsum text 就被当做占位符了,这种传统延续到了互联网时代。于此同时,孙悟空也在五指山下被压了500年,然后就进化成程序猿了,是不是很巧合。^_^", "


", - "Replace the text inside your p element with the first few words of this kitty ipsum text: Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff." + "把 p 标签的内容更换为:Monkey code 猴哥猴哥,你真了不得,金箍棒在手,问世间谁是英雄。" ], "tests": [ { - "text": "Your p element should contain the first few words of the provided kitty ipsum text.", - "testString": "assert.isTrue((/Kitty(\\s)+ipsum/gi).test($(\"p\").text()), 'Your p element should contain the first few words of the provided kitty ipsum text.');" + "text": "p 标签的内容必须包含 Monkey code。", + "testString": "assert.isTrue((/Monkey(\\s)+code/gi).test($(\"p\").text()), 'p 标签的内容必须包含 Monkey code。');" } ], "challengeType": 0, @@ -160,28 +158,28 @@ "id": "bad87fee1348bd9aedf08802", "title": "Uncomment HTML", "description": [ - "Commenting is a way that you can leave comments for other developers within your code without affecting the resulting output that is displayed the end user.", - "Commenting is also a convenient way to make code inactive without having to delete it entirely.", - "Comments in HTML starts with <!--, and ends with a -->", + "注释的作用是给代码添加一些说明,方便团队合作或日后自己查看,但又不影响代码本身。", + "注释也可以用来在不删除代码的前提下,让代码不起作用。", + "在 HTML 中,注释的开始标记是 <!--,结束标记是 -->。", "
", - "Uncomment your h1, h2 and p elements." + "现在我们反其道而行之,干掉 h1 标签、h2 标签、p 标签的注释。" ], "tests": [ { - "text": "Make your h1 element visible on your page by uncommenting it.", - "testString": "assert($(\"h1\").length > 0, 'Make your h1 element visible on your page by uncommenting it.');" + "text": "确保网页中能看到 h1 标签。", + "testString": "assert($(\"h1\").length > 0, '确保网页中能看到 h1 标签。');" }, { - "text": "Make your h2 element visible on your page by uncommenting it.", - "testString": "assert($(\"h2\").length > 0, 'Make your h2 element visible on your page by uncommenting it.');" + "text": "确保网页中能看到 h2 标签。", + "testString": "assert($(\"h2\").length > 0, '确保网页中能看到 h2 标签。');" }, { - "text": "Make your p element visible on your page by uncommenting it.", - "testString": "assert($(\"p\").length > 0, 'Make your p element visible on your page by uncommenting it.');" + "text": "确保网页中能看到 p 标签。", + "testString": "assert($(\"p\").length > 0, '确保网页中能看到 p 标签。');" }, { - "text": "Be sure to delete all trailing comment tags, i.e. -->.", - "testString": "assert(!/[^fc]-->/gi.test(code.replace(/ */gi.test(code.replace(/ *" ], "head": [], @@ -208,31 +206,31 @@ "id": "bad87fee1348bd9aedf08804", "title": "Comment out HTML", "description": [ - "Remember that in order to start a comment, you need to use <!-- and to end a comment, you need to use -->", - "Here you'll need to end the comment before your h2 element begins.", + "记住:注释的开始标记是 <!--,结束标记是 -->。", + "现在你需要在 h2 标签前终止注释。", "
", - "Comment out your h1 element and your p element, but not your h2 element." + "任务:h1 标签和 p 标签都注释掉,h2 标签保留。" ], "tests": [ { - "text": "Comment out your h1 element so that it is not visible on your page.", - "testString": "assert(($(\"h1\").length === 0), 'Comment out your h1 element so that it is not visible on your page.');" + "text": "注释掉 h1 标签,这样它就从网页上消失了。", + "testString": "assert(($(\"h1\").length === 0), '注释掉 h1 标签,这样它就从网页上消失了。');" }, { - "text": "Leave your h2 element uncommented so that it is visible on your page.", - "testString": "assert(($(\"h2\").length > 0), 'Leave your h2 element uncommented so that it is visible on your page.');" + "text": "h2 标签保持原样,这样网页上还能看到它。", + "testString": "assert(($(\"h2\").length > 0), 'h2 标签保持原样,这样网页上还能看到它。');" }, { - "text": "Comment out your p element so that it is not visible on your page.", - "testString": "assert(($(\"p\").length === 0), 'Comment out your p element so that it is not visible on your page.');" + "text": "注释掉 p 标签,这样它就从网页上消失了。", + "testString": "assert(($(\"p\").length === 0), '注释 p 标签,这样它就从网页上消失了。);" }, { - "text": "Be sure to close each of your comments with -->.", - "testString": "assert(code.match(/[^fc]-->/g).length > 1, 'Be sure to close each of your comments with -->.');" + "text": "确保每一个注释都以 --> 结尾。", + "testString": "assert(code.match(/[^fc]-->/g).length > 1, '确保每一个注释都以-->结尾。');" }, { - "text": "Do not change the order of the h1 h2 or p in the code.", - "testString": "assert((code.match(/<([a-z0-9]){1,2}>/g)[0]===\"

\" && code.match(/<([a-z0-9]){1,2}>/g)[1]===\"

\" && code.match(/<([a-z0-9]){1,2}>/g)[2]===\"

\") , 'Do not change the order of the h1 h2 or p in the code.');" + "text": "不要更改 h1 标签、h2 标签、p 标签的顺序。", + "testString": "assert((code.match(/<([a-z0-9]){1,2}>/g)[0]===\"

\" && code.match(/<([a-z0-9]){1,2}>/g)[1]===\"

\" && code.match(/<([a-z0-9]){1,2}>/g)[2]===\"

\") , '不要更改 h1 标签、h2 标签、p 标签的顺序。');" } ], "challengeType": 0, @@ -247,7 +245,7 @@ "", "

CatPhotoApp

", "", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", "-->" ], "head": [], @@ -259,23 +257,23 @@ "id": "bad87fed1348bd9aedf08833", "title": "Delete HTML Elements", "description": [ - "Our phone doesn't have much vertical space.", - "Let's remove the unnecessary elements so we can start building our CatPhotoApp.", + "手机的屏幕空间是有限的。", + "让我们删除不必要的标签,开始设计我们的 CatPhotoApp。", "
", - "Delete your h1 element so we can simplify our view." + "任务:删除 h1 标签以简化视图。" ], "tests": [ { - "text": "Delete your h1 element.", - "testString": "assert(($(\"h1\").length == 0), 'Delete your h1 element.');" + "text": "删除 h1 标签。", + "testString": "assert(($(\"h1\").length == 0), '删除 h1 标签。');" }, { - "text": "Leave your h2 element on the page.", - "testString": "assert(($(\"h2\").length > 0), 'Leave your h2 element on the page.');" + "text": "保留 h2 标签。", + "testString": "assert(($(\"h2\").length > 0), '保留 h2 标签。');" }, { - "text": "Leave your p element on the page.", - "testString": "assert(($(\"p\").length > 0), 'Leave your p element on the page.');" + "text": "保留 p 标签。", + "testString": "assert(($(\"p\").length > 0), '保留 p 标签。');" } ], "challengeType": 0, @@ -289,7 +287,7 @@ "", "

CatPhotoApp

", "", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

" + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

" ], "head": [], "tail": [] @@ -300,42 +298,42 @@ "id": "bad87fee1348bd9aecf08801", "title": "Introduction to HTML5 Elements", "description": [ - "HTML5 introduces more descriptive HTML tags. These include header, footer, nav, video, article, section and others.", - "These tags make your HTML easier to read, and also help with Search Engine Optimization (SEO) and accessibility.", - "The main HTML5 tag helps search engines and other developers find the main content of your page.", - "Note
Many of the new HTML5 tags and their benefits are covered in the Applied Accessibility section.", + "HTML5 引入了很多更具描述性的 HTML 标签,例如:headerfooternavvideoarticlesection 等等。", + "这些标签让 HTML 更易读,同时有助于搜索引擎优化和无障碍访问。", + "main 标签让搜索引擎和开发者瞬间就能找到网页的主要内容。", + "注意
在后面的应用无障碍课程中我们会接触到更多新的 HTML5 标签,以及明白它们的用处。", "
", - "Create a second p element after the existing p element with the following kitty ipsum text: Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.", - "Wrap the paragraphs with an opening and closing main tag." + "在现有的段落下创建一个新的段落,段落内容为:养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。", + "在第一个段落前添加
,在第二个段落后添加
。" ], "tests": [ { - "text": "You need 2 p elements with Kitty Ipsum text.", - "testString": "assert($(\"p\").length > 1, 'You need 2 p elements with Kitty Ipsum text.');" + "text": "页面中应该有两个段落。", + "testString": "assert($(\"p\").length > 1, '页面中应该有两个段落。');" }, { - "text": "Make sure each of your p elements has a closing tag.", - "testString": "assert(code.match(/<\\/p>/g) && code.match(/<\\/p>/g).length === code.match(/

p elements has a closing tag.');" + "text": "确保每个段落都有结束标记。", + "testString": "assert(code.match(/<\\/p>/g) && code.match(/<\\/p>/g).length === code.match(/

p element should contain the first few words of the provided additional kitty ipsum text.", - "testString": "assert.isTrue((/Purr\\s+jump\\s+eat/gi).test($(\"p\").text()), 'Your p element should contain the first few words of the provided additional kitty ipsum text.');" + "text": "新建的段落应该包含关键词:养猫。", + "testString": "assert.isTrue((/养猫/).test($(\"p\").text()), '新建的段落应该包含关键词:养猫。');" }, { - "text": "Your code should have one main element.", - "testString": "assert($('main').length === 1, 'Your code should have one main element.');" + "text": "代码中应该包含 main 标签。", + "testString": "assert($('main').length === 1, '代码中应该包含 main 标签。');" }, { - "text": "The main element should have two paragraph elements as children.", - "testString": "assert($(\"main\").children(\"p\").length === 2, 'The main element should have two paragraph elements as children.');" + "text": "main 标签应有两个 p 标签作为它的子标签。", + "testString": "assert($(\"main\").children(\"p\").length === 2, 'main 标签应有两个 p 标签作为它的子标签。');" }, { - "text": "The opening main tag should come before the first paragraph tag.", - "testString": "assert(code.match(/

\\s*?

/g), 'The opening main tag should come before the first paragraph tag.');" + "text": "开始标记

应位于第一个段落之前。", + "testString": "assert(code.match(/
\\s*?

/g), '开始标记

应位于第一个段落之前。');" }, { - "text": "The closing main tag should come after the second closing paragraph tag.", - "testString": "assert(code.match(/<\\/p>\\s*?<\\/main>/g), 'The closing main tag should come after the second closing paragraph tag.');" + "text": "结束标记
应位于第二段落之后。", + "testString": "assert(code.match(/<\\/p>\\s*?<\\/main>/g), '结束标记
应位于第二个段落之后。');" } ], "challengeType": 0, @@ -347,7 +345,7 @@ "contents": [ "

CatPhotoApp

", "", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

" + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

" ], "head": [], "tail": [] @@ -358,34 +356,34 @@ "id": "bad87fee1348bd9aedf08812", "title": "Add Images to Your Website", "description": [ - "You can add images to your website by using the img element, and point to a specific image's URL using the src attribute.", - "An example of this would be:", + "用 img 标签来为你的网站添加图片,其中 src 属性指向一个图片的地址。", + "举例如下:", "<img src=\"https://www.your-image-source.com/your-image.jpg\">", - "Note that img elements are self-closing.", - "All img elements must have an alt attribute. The text inside an alt attribute is used for screen readers to improve accessibility and is displayed if the image fails to load.", - "Note: If the image is purely decorative, using an empty alt attribute is a best practice.", - "Ideally the alt attribute should not contain special characters unless needed.", - "Let's add an alt attribute to our img example above:", - "<img src=\"https://www.your-image-source.com/your-image.jpg\" alt=\"Author standing on a beach with two thumbs up.\">", + "注意:img 标签是自关闭标签,不需要结束标记。", + "所有的 img 标签必须有 alt 属性,alt 属性的文本是当图片无法加载时显示的替代文本,这对于通过屏幕阅读器来浏览网页的用户非常重要。", + "注意:如果图片是纯装饰性的,用一个空的 alt 是最佳实践。", + "理想情况下,alt属性不应该包含特殊字符,除非需要。", + "让我们给上面例子的 img 添加 alt 属性。", + "<img src=\"https://www.your-image-source.com/your-image.jpg\" alt=\"作者站在沙滩上竖起两个大拇指\">", "
", - "Let's try to add an image to our website:", - "Insert an img tag, before the h2 element.", - "Now set the src attribute so that it points to this url:", + "让我们给网站添加图片:", + "在 h2 标签前,插入一个 img 标签", + "现在设置 src 属性指向这个地址:", "https://bit.ly/fcc-relaxing-cat", - "Finally don't forget to give your image an alt text." + "最后不要忘记给图片添加一个 alt 文本。" ], "tests": [ { - "text": "Your page should have an image element.", - "testString": "assert($(\"img\").length > 0, 'Your page should have an image element.');" + "text": "网页应该有一张图片。", + "testString": "assert($(\"img\").length > 0, '网页应该有一张图片。');" }, { - "text": "Your image should have a src attribute that points to the kitten image.", - "testString": "assert(new RegExp(\"\\/\\/bit.ly\\/fcc-relaxing-cat|\\/\\/s3.amazonaws.com\\/freecodecamp\\/relaxing-cat.jpg\", \"gi\").test($(\"img\").attr(\"src\")), 'Your image should have a src attribute that points to the kitten image.');" + "text": "这张图片应该是一只小猫。", + "testString": "assert(new RegExp(\"\\/\\/bit.ly\\/fcc-relaxing-cat|\\/\\/s3.amazonaws.com\\/freecodecamp\\/relaxing-cat.jpg\", \"gi\").test($(\"img\").attr(\"src\")), '这张图片应该是一只小猫。');" }, { - "text": "Your image element must have an alt attribute.", - "testString": "assert(code.match(/alt\\s*?=\\s*?(\\\"|\\').*(\\\"|\\')/), 'Your image element must have an alt attribute.');" + "text": "图片必须有 alt 属性。", + "testString": "assert(code.match(/alt\\s*?=\\s*?(\\\"|\\').*(\\\"|\\')/), '图片必须有 alt 属性。');" } ], "challengeType": 0, @@ -400,8 +398,8 @@ "
", " ", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "
" ], "head": [], @@ -413,25 +411,25 @@ "id": "bad87fee1348bd9aedf08816", "title": "Link to External Pages with Anchor Elements", "description": [ - "You can use anchor elements to link to content outside of your web page.", - "anchor elements need a destination web address called an href attribute. They also need anchor text. Here's an example:", + "你可以用锚点(Anchor,简写 a)来实现网页间的跳转。", + "锚点需要一个 href 属性指向目的地,它还需要有锚点文本,例如:", "<a href=\"https://freecodecamp.org\">this links to freecodecamp.org</a>", - "Then your browser will display the text \"this links to freecodecamp.org\" as a link you can click. And that link will take you to the web address https://www.freecodecamp.org.", + "然后你的浏览器会显示一个可以点击的文本,点击该文本就会跳转到 https://www.freecodecamp.org。", "
", - "Create an a element that links to http://freecatphotoapp.com and has \"cat photos\" as its anchor text." + "创建一个 a 标签,href 属性为 http://freecatphotoapp.com ,锚点文本为:cat photos。" ], "tests": [ { - "text": "Your a element should have the anchor text of \"cat photos\".", - "testString": "assert((/cat photos/gi).test($(\"a\").text()), 'Your a element should have the anchor text of \"cat photos\".');" + "text": "a 标签的锚点文本应为:cat photos。", + "testString": "assert((/cat photos/gi).test($(\"a\").text()), 'a 标签的锚点文本应为:cat photos。');" }, { - "text": "You need an a element that links to http://freecatphotoapp.com", - "testString": "assert(/http:\\/\\/(www\\.)?freecatphotoapp\\.com/gi.test($(\"a\").attr(\"href\")), 'You need an a element that links to http://freecatphotoapp.com');" + "text": "a 标签的 href 属性应为:\"http://freecatphotoapp.com\"。", + "testString": "assert(/http:\\/\\/(www\\.)?freecatphotoapp\\.com/gi.test($(\"a\").attr(\"href\")), 'a 标签的 href 属性应为:\"http://freecatphotoapp.com\"。');" }, { - "text": "Make sure your a element has a closing tag.", - "testString": "assert(code.match(/<\\/a>/g) && code.match(/<\\/a>/g).length === code.match(/a element has a closing tag.');" + "text": "确保 a 标签有结束标记。", + "testString": "assert(code.match(/<\\/a>/g) && code.match(/<\\/a>/g).length === code.match(/a 标签有结束标记。');" } ], "challengeType": 0, @@ -448,8 +446,8 @@ " ", " \"A", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "
" ], "head": [], @@ -461,40 +459,40 @@ "id": "bad88fee1348bd9aedf08816", "title": "Link to Internal Sections of a Page with Anchor Elements", "description": [ - "Anchor elements can also be used to create internal links to jump to different sections within a webpage.", - "To create an internal link, you assign a link's href attribute to a hash symbol # plus the value of the id attribute for the element that you want to internally link to, usually further down the page. You then need to add the same id attribute to the element you are linking to. An id is an attribute that uniquely describes an element.", - "Below is an example of an internal anchor link and its target element:", + "锚点同样也可以用来在网页内不同区域的跳转。", + "用一个井号 # 加上你想跳转到的区域对应的 id 属性值,通过把它作为锚点的 href 属性值来创建一个内部链接。 id 是用来描述网页元素的一个属性,它的值在整个页面中唯一。", + "下面是用来创建内部锚点链接的例子:", "
<a href=\"#contacts-header\">Contacts</a>
...
<h2 id=\"contacts-header\">Contacts</h2>
", - "When users click the Contacts link, they'll be taken to the section of the webpage with the Contacts header element.", + "当用户点击了 Contacts 链接,页面就会跳转到网页的 Contacts 区域。", "
", - "Change your external link to an internal link by changing the href attribute to \"#footer\" and the text from \"cat photos\" to \"Jump to Bottom\".", - "Remove the target=\"_blank\" attribute from the anchor tag since this causes the linked document to open in a new window tab.", - "Then add an id attribute with a value of \"footer\" to the <footer> element at the bottom of the page." + "通过修改 href 属性为 #footer 来更改外部链接为内部链接,同时修改文本 cat photosJump to Bottom。", + "移除 target=\"_blank\" 属性避免点击链接会打开新的标签页。", + "然后添加一个 <footer> 标签,它的 id 值为 footer。" ], "tests": [ { - "text": "There should be only one anchor tag on your page.", - "testString": "assert($('a').length == 1, 'There should be only one anchor tag on your page.');" + "text": "页面中应该只有一个锚点。", + "testString": "assert($('a').length == 1, '页面中应该只有一个锚点。');" }, { - "text": "There should be only one footer tag on your page.", - "testString": "assert($('footer').length == 1, 'There should be only one footer tag on your page.');" + "text": "页面中应该只有一个 footer 标签。", + "testString": "assert($('footer').length == 1, '页面中应该只有一个 footer 标签。');" }, { - "text": "The a tag should have an href attribute set to \"#footer\".", - "testString": "assert($('a').eq(0).attr('href') == \"#footer\", 'The a tag should have an href attribute set to \"#footer\".');" + "text": "a 标签的 href 属性应为:\"#footer\"。", + "testString": "assert($('a').eq(0).attr('href') == \"#footer\", 'a 标签的 href 属性应为:\"#footer\"。');" }, { - "text": "The a tag should not have a target attribute", - "testString": "assert(typeof $('a').eq(0).attr('target') == typeof undefined || $('a').eq(0).attr('target') == true, 'The a tag should not have a target attribute');" + "text": "a 标签不应该有 target 属性。", + "testString": "assert(typeof $('a').eq(0).attr('target') == typeof undefined || $('a').eq(0).attr('target') == true, 'a 标签不应该有 target 属性。');" }, { - "text": "The a text should be \"Jump to Bottom\".", - "testString": "assert($('a').eq(0).text().match(/Jump to Bottom/gi), 'The a text should be \"Jump to Bottom\".');" + "text": "a 标签的文本应为 Jump to Bottom。", + "testString": "assert($('a').eq(0).text().match(/Jump to Bottom/gi), 'a 标签的文本应为 Jump to Bottom。');" }, { - "text": "The footer tag should have an id attribute set to \"footer\".", - "testString": "assert($('footer').eq(0).attr('id') == \"footer\", 'The footer tag should have an id attribute set to \"footer\".');" + "text": "footer 标签的 id 属性应为 \"footer\"。", + "testString": "assert($('footer').eq(0).attr('id') == \"footer\", 'footer 标签的 id 属性应为 \"footer\"。');" } ], "challengeType": 0, @@ -511,10 +509,8 @@ " ", " \"A", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", - "

Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.

", - "

Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。 养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。 在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。 在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。 养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", " ", "
", " ", @@ -529,50 +525,50 @@ "id": "bad87fee1348bd9aede08817", "title": "Nest an Anchor Element within a Paragraph", "description": [ - "You can nest links within other text elements.", + "你可以在其他文本标签内嵌套链接。You can nest links within other text elements.", "
<p>
Here's a <a target=\"_blank\" href=\"http://freecodecamp.org\"> link to freecodecamp.org</a> for you to follow.
</p>
", - "Let's break down the example:", - "Normal text is wrapped in the p element:
<p> Here's a ... for you to follow. </p>", - "Next is the anchor element <a> (which requires a closing tag </a>):
<a> ... </a>", - "target is an anchor tag attribute that specifies where to open the link and the value \"_blank\" specifies to open the link in a new tab", - "href is an anchor tag attribute that contains the URL address of the link:
<a href=\"http://freecodecamp.org\"> ... </a>", - "The text, \"link to freecodecamp.org\", within the anchor element called anchor text, will display a link to click:
<a href=\" ... \">link to freecodecamp.org</a>", - "The final output of the example will look like this:

Here's a link to freecodecamp.org for you to follow.

", + "让我们来分解这个例子:", + "通常,文本是被包裹在 p 标签内:
<p> Here's a ... for you to follow. </p>", + "接下来是 anchor 标签 <a>(需要结束标记 </a>):
<a> ... </a>", + "target 是锚点标签的一个属性,它指定了会以什么方式来打开链接,属性值 \"_blank\" 的意思是链接会在新标签页打开。", + "href 是锚点标签的另一个属性:它指定了链接的 URL 地址:
<a href=\"http://freecodecamp.org\"> ... </a>", + "锚点标签内的文本:\"link to freecodecamp.org\",会显示为一个可以点击的链接:
<a href=\" ... \">link to freecodecamp.org</a>", + "例子的最后输出将会是这样:

Here's a link to freecodecamp.org for you to follow.

", "
", - "Now nest your existing a element within a new p element (just after the existing main element). The new paragraph should have text that says \"View more cat photos\", where \"cat photos\" is a link, and the rest of the text is plain text." + "现在用一个新的 p 标签来包裹现存的 a 标签(必须放在 main 标签之后才行)。新段落的文本为:View more cat photos,其中 \"cat photos\" 是一个链接,其他是纯文本。" ], "tests": [ { - "text": "You need an a element that links to \"http://freecatphotoapp.com\".", - "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").length > 0 || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").length > 0), 'You need an a element that links to \"http://freecatphotoapp.com\".');" + "text": "你需要一个指向 \"http://freecatphotoapp.com\" 的锚点。", + "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").length > 0 || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").length > 0), '你需要一个指向 \"http://freecatphotoapp.com\" 的锚点。');" }, { - "text": "Your a element should have the anchor text of \"cat photos\"", - "testString": "assert($(\"a\").text().match(/cat\\sphotos/gi), 'Your a element should have the anchor text of \"cat photos\"');" + "text": "锚点文本为应为:cat photos。", + "testString": "assert($(\"a\").text().match(/cat\\sphotos/gi), '锚点文本为应为:cat photos。');" }, { - "text": "Create a new p element around your a element. There should be at least 3 total p tags in your HTML code.", - "testString": "assert($(\"p\") && $(\"p\").length > 2, 'Create a new p element around your a element. There should be at least 3 total p tags in your HTML code.');" + "text": "在锚点的外部创建一个新段落,这样页面就有3个段落了。", + "testString": "assert($(\"p\") && $(\"p\").length > 2, '在锚点的外部创建一个段落,这样页面就有3个段落了。');" }, { - "text": "Your a element should be nested within your new p element.", - "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").parent().is(\"p\") || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().is(\"p\")), 'Your a element should be nested within your new p element.');" + "text": "锚点应嵌套在新段落内。", + "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").parent().is(\"p\") || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().is(\"p\")), '锚点应嵌套在新段落内。');" }, { - "text": "Your p element should have the text \"View more \" (with a space after it).", - "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").parent().text().match(/View\\smore\\s/gi) || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().text().match(/View\\smore\\s/gi)), 'Your p element should have the text \"View more \" (with a space after it).');" + "text": "段落的文本应为:View more (记得 more 后面有一个空格)。", + "testString": "assert(($(\"a[href=\\\"http://freecatphotoapp.com\\\"]\").parent().text().match(/View\\smore\\s/gi) || $(\"a[href=\\\"http://www.freecatphotoapp.com\\\"]\").parent().text().match(/View\\smore\\s/gi)), '段落的文本应为:View more (记得 more 后面有一个空格)。');" }, { - "text": "Your a element should not have the text \"View more\".", - "testString": "assert(!$(\"a\").text().match(/View\\smore/gi), 'Your a element should not have the text \"View more\".');" + "text": "锚点的文本不应该为:View more。", + "testString": "assert(!$(\"a\").text().match(/View\\smore/gi), '锚点的文本不应该为:View more。');" }, { - "text": "Make sure each of your p elements has a closing tag.", - "testString": "assert(code.match(/<\\/p>/g) && code.match(/

/g).length === code.match(/

p elements has a closing tag.');" + "text": "确保每个段落有结束标记。", + "testString": "assert(code.match(/<\\/p>/g) && code.match(/

/g).length === code.match(/

a elements has a closing tag.", - "testString": "assert(code.match(/<\\/a>/g) && code.match(//g).length === code.match(/a elements has a closing tag.');" + "text": "确保每个段落有结束标记。", + "testString": "assert(code.match(/<\\/a>/g) && code.match(//g).length === code.match(/", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "" ], "head": [], @@ -627,8 +623,8 @@ " ", " \"A", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "" ], "head": [], @@ -675,8 +671,8 @@ " ", " \"A", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "" ], "head": [], @@ -727,8 +723,8 @@ " ", "
\"A", " ", - "

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", - "

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", + "

养猫有的时候,就是介于爱与恨之间,当你钦羡别人萌宠这么可爱的时候,你一定没有想过,猫咪会到处掉毛,甚至会屯老鼠,啃鞋子,用爪子爬门,你不理它,它就挠你,你要对它发脾气,它会比你更来劲。所以,猫咪慎入,没有一定的准备,切勿随便去侍养动物。它们一旦认定你了,你就是它们的主人,如果你抛弃它们,它们必定心中重创。

", "" ], "head": [], @@ -1469,7 +1465,7 @@ " The best page ever", " ", "

The best page ever

", - "

Cat ipsum dolor sit amet, jump launch to pounce upon little yarn mouse, bare fangs at toy run hide in litter box until treats are fed. Go into a room to decide you didn't want to be in there anyway. I like big cats and i can not lie kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Meow i could pee on this if i had the energy for slap owner's face at 5am until human fills food dish yet scamper. Knock dish off table head butt cant eat out of my own dish scratch the furniture. Make meme, make cute face. Sleep in the bathroom sink chase laser but pee in the shoe. Paw at your fat belly licks your face and eat grass, throw it back up kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

", + "

在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。 在大家心目中,猫是慵懒和可爱的化身,它可以睡饱了再起来吃饭,可以逗趣小耗子,可以卖得了萌,使得了坏,这样百变的小怪兽就集结在一只宠物上,怎能不惹人怜爱。

", " ", " " ], diff --git a/01-responsive-web-design/basic-html-and-html5.md b/01-responsive-web-design/basic-html-and-html5.md new file mode 100644 index 0000000..6693e7e --- /dev/null +++ b/01-responsive-web-design/basic-html-and-html5.md @@ -0,0 +1,34 @@ +# Introduction to Basic HTML & HTML5 # + +HTML, or HyperText Markup Language, is a markup language used to describe the structure of a web page. It uses a special syntax or notation to organize and give information about the page to the browser. Elements usually have opening and closing tags that surround and give meaning to content. For example, there are different tag options to place around text to show whether it is a heading, a paragraph, or a list. + +For example: + +``` +

Top level heading: Maybe a page title

+ +

A paragraph of text. Some information we would like to communicate to the viewer. This can be as long or short as we would like.

+ +
    +
  1. Number one on the list
  2. +
  3. Number two
  4. +
  5. A third item
  6. +
+``` + +Becomes: + +# Top level heading: Maybe a page title # + +A paragraph of text. Some information we would like to communicate to the user. This can be as long or short as we would like. + +1、Number one on the list +2、Number two +3、A third item + + +The HyperText part of HTML comes from the early days of the web and its original use case. Pages usually contained static documents that contained references to other documents. These references contained hypertext links used by the browser to navigate to the reference document so the user could read the reference document without having to manually search for it. + +As web pages and web applications grow more complex, the W3 Consortium updates the HTML specification to ensure that a webpage can be shown reliably on any browser. The latest version of HTML is HTML5. + +This section introduces how to use HTML elements to give structure and meaning to your web content. \ No newline at end of file diff --git a/01-responsive-web-design/css-flexbox.md b/01-responsive-web-design/css-flexbox.md new file mode 100644 index 0000000..e38623e --- /dev/null +++ b/01-responsive-web-design/css-flexbox.md @@ -0,0 +1,5 @@ +# Introduction to the CSS Flexbox Challenges # + +A website's User Interface ("UI") has two components. First, there are the visual elements, such as colors, fonts, and images. Second, there is the placement or positioning of those elements. In Responsive Web Design, a UI layout must accommodate many different browsers and devices accessing the content. + +CSS3 introduced Flexible Boxes, or flexbox, to create page layouts for a dynamic UI. It is a layout mode that arranges elements in a predictable way for different screen sizes and browsers. While somewhat new, all popular modern browsers support flexbox. This section covers how to use flexbox and the different layout options it offers. diff --git a/01-responsive-web-design/css-grid.json b/01-responsive-web-design/css-grid.json index 159f623..e3d7d90 100644 --- a/01-responsive-web-design/css-grid.json +++ b/01-responsive-web-design/css-grid.json @@ -1,1492 +1,1492 @@ { - "name": "CSS Grid", - "order": 6, - "time": "5 hours", - "helpRoom": "Help", - "challenges": [ - { - "id": "5a858944d96184f06fd60d61", - "title": "Create Your First CSS Grid", - "description": [ - "Turn any HTML element into a grid container by setting its display property to grid. This gives you the ability to use all the other properties associated with CSS Grid.", - "Note
In CSS Grid, the parent element is referred to as the container and its children are called items.", - "
", - "Change the display of the div with the container class to grid." - ], - "tests": [ - { - "text": "container class should have a display property with a value of grid.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*display\\s*?:\\s*?grid\\s*?;[\\s\\S]*}/gi), 'container class should have a display property with a value of grid.');" + "name": "CSS Grid", + "order": 6, + "time": "5 hours", + "helpRoom": "Help", + "challenges": [ + { + "id": "5a858944d96184f06fd60d61", + "title": "Create Your First CSS Grid", + "description": [ + "通过将属性display的值设为grid,使 HTML 元素变为网格容器。通过前面的操作,你可以对该容器使用与 CSS 网格(CSS Grid)相关的属性。", + "注意:
在 CSS 网格中,父元素称为容器(container),它的子元素称为项(items)。", + "
", + "将类为container的 div 的display属性改为grid。" + ], + "tests": [ + { + "text": "container类应该有display属性且值为grid。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*display\\s*?:\\s*?grid\\s*?;[\\s\\S]*}/gi), 'container类应该有display属性且值为grid。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "Feb 15, 2018", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "Feb 15, 2018", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a9036d038fddaf9a66b5d32", + "title": "Add Columns with grid-template-columns", + "description": [ + "简单地添加一个网格元素并不能取得很大的进展。你还需要明确网格的结构。在一个网格容器中使用grid-template-columns属性可以添加一些列,示例如下:", + "
.container {
  display: grid;
  grid-template-columns: 50px 50px;
}
", + "上面的代码可以在网格容器中添加两列,宽度均为 50px。", + "grid-template-columns属性值的个数表示网格的列数,而每个值表示对应列的宽度。", + "
", + "给网格容器放置三个列,每列宽度均为100px。" + ], + "tests": [ + { + "text": "container类应该有grid-template-columns属性且有三个100px作为值。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?100px\\s*?100px\\s*?100px\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-columns属性且有三个100px作为值。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "Feb 15, 2018", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a9036d038fddaf9a66b5d32", - "title": "Add Columns with grid-template-columns", - "description": [ - "Simply creating a grid element doesn't get you very far. You need to define the structure of the grid as well. To add some columns to the grid, use the grid-template-columns property on a grid container as demonstrated below:", - "
.container {
  display: grid;
  grid-template-columns: 50px 50px;
}
", - "This will give your grid two columns that are 50px wide each.", - "The number of parameters given to the grid-template-columns property indicates the number of columns in the grid, and the value of each parameter indicates the width of each column.", - "
", - "Give the grid container three columns that are 100px wide each." - ], - "tests": [ - { - "text": "container class should have a grid-template-columns property with three units of 100px.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?100px\\s*?100px\\s*?100px\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-columns property with three units of 100px.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "Feb 15, 2018", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a9036e138fddaf9a66b5d33", - "title": "Add Rows with grid-template-rows", - "description": [ - "The grid you created in the last challenge will set the number of rows automatically. To adjust the rows manually, use the grid-template-rows property in the same way you used grid-template-columns in previous challenge.", - "
", - "Add two rows to the grid that are 50px tall each." - ], - "tests": [ - { - "text": "container class should have a grid-template-rows property with two units of 50px.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-rows\\s*?:\\s*?50px\\s*?50px\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-rows property with two units of 50px.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a9036ee38fddaf9a66b5d34", - "title": "Use CSS Grid units to Change the Size of Columns and Rows", - "description": [ - "You can use absolute and relative units like px and em in CSS Grid to define the size of rows and columns. You can use these as well:", - "fr: sets the column or row to a fraction of the available space,", - "auto: sets the column or row to the width or height of its content automatically,", - "%: adjusts the column or row to the percent width of its container.", - "Here's the code that generates the output in the preview:", - "
grid-template-columns: auto 50px 10% 2fr 1fr;
", - "This snippet creates five columns. The first column is as wide as its content, the second column is 50px, the third column is 10% of its container, and for the last two columns; the remaining space is divided into three sections, two are allocated for the fourth column, and one for the fifth.", - "
", - "Make a grid with three columns whose widths are as follows: 1fr, 100px, and 2fr." - ], - "tests": [ - { - "text": "container class should have a grid-template-columns property that has three columns with the following widths: 1fr, 100px, and 2fr.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?1fr\\s*?100px\\s*?2fr\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-columns property that has three columns with the following widths: 1fr, 100px, and 2fr.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a9036ee38fddaf9a66b5d35", - "title": "Create a Column Gap Using grid-column-gap", - "description": [ - "So far in the grids you have created, the columns have all been tight up against each other. Sometimes you want a gap in between the columns. To add a gap between the columns, use the grid-column-gap property like this:", - "
grid-column-gap: 10px;
", - "This creates 10px of empty space between all of our columns.", - "
", - "Give the columns in the grid a 20px gap." - ], - "tests": [ - { - "text": "container class should have a grid-column-gap property that has the value of 20px.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-column-gap\\s*?:\\s*?20px\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-column-gap property that has the value of 20px.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a9036e138fddaf9a66b5d33", + "title": "Add Rows with grid-template-rows", + "description": [ + "在上次挑战中,你创建的网格会自动设置行数。你可以像用grid-template-columns设置网格的列一样,用grid-template-rows为网格设置行数。", + "
", + "给网格添加两行,使每行高度均为50px。" + ], + "tests": [ + { + "text": "container类应该有grid-template-rows属性,且值为两个50px。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-rows\\s*?:\\s*?50px\\s*?50px\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-rows属性,且值为两个50px。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a9036ee38fddaf9a66b5d36", - "title": "Create a Row Gap using grid-row-gap", - "description": [ - "You can add a gap in between the rows of a grid using grid-row-gap in the same way that you added a gap in between columns in the previous challenge.", - "
", - "Create a gap for the rows that is 5px tall." - ], - "tests": [ - { - "text": "container class should have a grid-row-gap property that has the value of 5px.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-row-gap\\s*?:\\s*?5px\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-row-gap property that has the value of 5px.');" + }, + { + "id": "5a9036ee38fddaf9a66b5d34", + "title": "Use CSS Grid units to Change the Size of Columns and Rows", + "description": [ + "在 CSS 网格中,可以使用绝对定位和相对定位单位如pxem来确定行或列的大小。下面的单位也可以使用:", + "fr:设置列或行占剩余空间的一个比例,", + "auto:设置列宽或行高自动等于它的内容的宽度或高度,", + "%:将列或行调整为它的容器宽度或高度的百分比,", + "最右侧的预览区中的效果通过下面的代码实现:", + "
grid-template-columns: auto 50px 10% 2fr 1fr;
", + "这段代添加了五个列。第一列的宽与它的内容宽度相等;第二列宽 50px;第三列宽是它容器的 10%;最后两列,将剩余的宽度平均分成三份,第四列占两份,第五列占一份。", + "
", + "生成一个包含三列的网格,每列宽度分别为:1fr,100px,和 2fr。" + ], + "tests": [ + { + "text": "container类应该有grid-template-columns属性,且生成宽为1fr, 100px2fr的三列。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?1fr\\s*?100px\\s*?2fr\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-columns属性,且生成宽为1fr, 100px2fr的三列。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a9036ee38fddaf9a66b5d35", + "title": "Create a Column Gap Using grid-column-gap", + "description": [ + "到目前为止,在你所建立的网格中列都相互紧挨着。如果需要在列与列之间添加一些间隙,我们可以使用grid-column-gap:", + "
grid-column-gap: 10px;
", + "这会在我们创建的所有列之间添加 10px 的空白间隙。", + "
", + "为网格中的列添加宽度为20px的间隙。" + ], + "tests": [ + { + "text": "container类应该有grid-column-gap属性且值为20px。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-column-gap\\s*?:\\s*?20px\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-column-gap属性且值为20px。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a9036ee38fddaf9a66b5d37", - "title": "Add Gaps Faster with grid-gap", - "description": [ - "grid-gap is a shorthand property for grid-row-gap and grid-column-gap from the previous two challenges that's more convenient to use. If grid-gap has one value, it will create a gap between all rows and columns. However, if there are two values, it will use the first one to set the gap between the rows and the second value for the columns.", - "
", - "Use grid-gap to introduce a 10px gap between the rows and 20px gap between the columns." - ], - "tests": [ - { - "text": "container class should have a grid-gap property that introduces 10px gap between the rows and 20px gap between the columns.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-gap\\s*?:\\s*?10px\\s*?20px\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-gap property that introduces 10px gap between the rows and 20px gap between the columns.');" + }, + { + "id": "5a9036ee38fddaf9a66b5d36", + "title": "Create a Row Gap using grid-row-gap", + "description": [ + "和上个挑战在两列之间添加间隙一样,你可以用grid-row-gap在两行之间添加间隙。", + "
", + "为网格中的行添加高度为5px的间隙。" + ], + "tests": [ + { + "text": "container类应该有grid-row-gap属性且值为5px。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-row-gap\\s*?:\\s*?5px\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-row-gap属性且值为5px。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a9036ee38fddaf9a66b5d37", + "title": "Add Gaps Faster with grid-gap", + "description": [ + "grid-gapgrid-row-gapgrid-column-gap的简写,它更方便使用。如果grid-gap有一个值,行与行之间和列与列之间将添加等于该值的间隙。但是,如果有两个值,第一个值将作为行间隙的高度值,第二个值是列间隙的宽度值。", + "
", + "使用grid-gap在行之间添加10px的间隙,在列之间添加20px的间隙。" + ], + "tests": [ + { + "text": "container类应该有grid-gap属性,在行之间引入10px的间隙,在列之间引入20px的间隙。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-gap\\s*?:\\s*?10px\\s*?20px\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-gap属性,在行之间引入10px的间隙,在列之间引入20px的间隙。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a90372638fddaf9a66b5d38", - "title": "Use grid-column to Control Spacing", - "description": [ - "Up to this point, all the properties that have been discussed are for grid containers. The grid-column property is the first one for use on the grid items themselves.", - "The hypothetical horizontal and vertical lines that create the grid are referred to as lines. These lines are numbered starting with 1 at the top left corner of the grid and move right for columns and down for rows, counting upward.", - "This is what the lines look like for a 3x3 grid:", - "

column lines

1

2

3

4

row lines

1

2

3

4

", - "To control the amount of columns an item will consume, you can use the grid-column property in conjunction with the line numbers you want the item to start and stop at.", - "Here's an example:", - "
grid-column: 1 / 3;
", - "This will make the item start at the first vertical line of the grid on the left and span to the 3rd line of the grid, consuming two columns.", - "
", - "Make the item with the class item5 consume the last two columns of the grid." - ], - "tests": [ - { - "text": "item5 class should have a grid-column property that has the value of 2 / 4.", - "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-column\\s*?:\\s*?2\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5 class should have a grid-column property that has the value of 2 / 4.');" + }, + { + "id": "5a90372638fddaf9a66b5d38", + "title": "Use grid-column to Control Spacing", + "description": [ + "到目前为止,所有的讨论都是围绕网格容器的。grid-column属性是第一个用于网格项本身的属性。", + "网格的假想水平线和垂直线被称为线(lines)。这些线在网格的左上角从 1 开始编号,垂直线向右、水平线向下累加计数。", + "这是一个 3x3 网格的线条:", + "

column lines

1

2

3

4

row lines

1

2

3

4

", + "你可以用grid-column属性定义网格项开始和结束的位置,进而控制每个网格项占用的列数。", + "示例如下:", + "
grid-column: 1 / 3;
", + "这会让网格项从左侧第一条线开始到第三条线结束,占用两列。", + "
", + "使类为item5的网格项占用网格的最后两列。" + ], + "tests": [ + { + "text": "item5类应该有grid-column属性且其值为2 / 4。", + "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-column\\s*?:\\s*?2\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5类应该有grid-column属性且其值为2 / 4。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a90373638fddaf9a66b5d39", + "title": "Use grid-row to Control Spacing", + "description": [ + "当然,你可以像列一样使网格项跨越多行。对于一个网格项,你可以用grid-row属性来确定开始和结束的水平线。", + "
", + "使类为item5的元素占用最后两行。" + ], + "tests": [ + { + "text": "item5类应该有grid-row属性且值为2 / 4。", + "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-row\\s*?:\\s*?2\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5类应该有grid-row属性且值为2 / 4。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a90373638fddaf9a66b5d39", - "title": "Use grid-row to Control Spacing", - "description": [ - "Of course, you can make items consume multiple rows just like you can with columns. You define the horizontal lines you want an item to start and stop at using the grid-row property on a grid item.", - "
", - "Make the element with the item5 class consume the last two rows." - ], - "tests": [ - { - "text": "item5 class should have a grid-row property that has the value of 2 / 4.", - "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-row\\s*?:\\s*?2\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5 class should have a grid-row property that has the value of 2 / 4.');" + }, + { + "id": "5a90374338fddaf9a66b5d3a", + "title": "Align an Item Horizontally using justify-self", + "description": [ + "在 CSS 网格中,每个网格项的内容分别位于被称为单元格(cell)的框内。你可以使用网格项的justify-self属性,设置其内容的位置在单元格内沿行轴对齐的方式。默认情况下,这个属性的值是stretch,这将使内容占满整个单元格的宽度。该 CSS 网格属性也可以使用其他的值:", + "start:使内容在单元格左侧对齐,", + "center:使内容在单元格居中对齐,", + "end:使内容在单元格右侧对齐,", + "
", + "使用justify-self属性让类为item2的网格项居中。" + ], + "tests": [ + { + "text": "item2类应该有justify-self属性且值为center。", + "testString": "assert(code.match(/.item2\\s*?{[\\s\\S]*justify-self\\s*?:\\s*?center\\s*?;[\\s\\S]*}/gi), 'item2类应该有justify-self属性且值为center。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a90375238fddaf9a66b5d3b", + "title": "Align an Item Vertically using align-self", + "description": [ + "正如能设置网格项沿行轴对齐方式一样,也可以设置网格项沿列轴对齐方式:你可以对网格项使用align-self属性。对于该属性,你能使用在上一个挑战中可用于justify-self属性的任一个值。", + "
", + "用值end使类为item3的网格项底端对齐。" + ], + "tests": [ + { + "text": "item3类应该有align-self属性且值为end。", + "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*align-self\\s*?:\\s*?end\\s*?;[\\s\\S]*}/gi), 'item3类应该有align-self属性且值为end。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a90374338fddaf9a66b5d3a", - "title": "Align an Item Horizontally using justify-self", - "description": [ - "In CSS Grid, the content of each item is located in a box which is referred to as a cell. You can align the content's position within its cell horizontally using the justify-self property on a grid item. By default, this property has a value of stretch, which will make the content fill the whole width of the cell. This CSS Grid property accepts other values as well:", - "start: aligns the content at the left of the cell,", - "center: aligns the content in the center of the cell,", - "end: aligns the content at the right of the cell.", - "
", - "Use the justify-self property to center the item with the class item2." - ], - "tests": [ - { - "text": "item2 class should have a justify-self property that has the value of center.", - "testString": "assert(code.match(/.item2\\s*?{[\\s\\S]*justify-self\\s*?:\\s*?center\\s*?;[\\s\\S]*}/gi), 'item2 class should have a justify-self property that has the value of center.');" + }, + { + "id": "5a90376038fddaf9a66b5d3c", + "title": "Align All Items Horizontally using justify-items", + "description": [ + "有时你想让在 CSS 网格中的网格项共享对齐方式。你可以像之前学习的那样单独使他们对齐,也可以对网格容器使用justify-items使它们一次性沿行轴对齐。对于这个属性你能使用在之前的两个挑战中学到的所有值,与之前不同的是,它将使网格中所有的网格项按所设置的方式对齐。", + "
", + "使用本次挑战所学的属性设置所有网格项水平居中。" + ], + "tests": [ + { + "text": "container类应该有justify-items属性且值为center。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*justify-items\\s*?:\\s*?center\\s*?;[\\s\\S]*}/gi), 'container类应该有justify-items属性且值为center。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a94fdf869fb03452672e45b", + "title": "Align All Items Vertically using align-items", + "description": [ + "对网格容器使用align-items属性可以给网格中所有的网格项设置沿列轴对齐的方式。", + "
", + "请使用它让所有网格项移动到单元格的末尾。" + ], + "tests": [ + { + "text": "container类应该有align-items属性且值为end。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*align-items\\s*?:\\s*?end\\s*?;[\\s\\S]*}/gi), 'container类应该有align-items属性且值为end。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a90375238fddaf9a66b5d3b", - "title": "Align an Item Vertically using align-self", - "description": [ - "Just as you can align an item horizontally, there's a way to align an item vertically as well. To do this, you use the align-self property on an item. This property accepts all of the same values as justify-self from the last challenge.", - "
", - "Align the item with the class item3 vertically at the end." - ], - "tests": [ - { - "text": "item3 class should have a align-self property that has the value of end.", - "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*align-self\\s*?:\\s*?end\\s*?;[\\s\\S]*}/gi), 'item3 class should have a align-self property that has the value of end.');" + }, + { + "id": "5a94fe0569fb03452672e45c", + "title": "Divide the Grid Into an Area Template", + "description": [ + "你可以将网格中的一些网格单元格组合成一个区域(area),并为该区域指定一个自定义名称。你可以通过给容器加上grid-template-areas来实现:", + "
grid-template-areas:
  \"header header header\"
  \"advert content content\"
  \"footer footer footer\";
", + "上面的代码将顶部三个单元格合并成一个名为header的区域,将底部三个单元格合并为一个名为footer的区域,并在中间行生成两个区域————advertcontent。", + "注意:
在代码中,每个单词代表一个网格单元格,每对引号代表一行。", + "除了自定义标签,你还能使用句点(.)来表示一个空单元格", + "
", + "请放置区域模板,让名为advert的区域变成空单元格。" + ], + "tests": [ + { + "text": "container类应该有类似于最右侧预览区的grid-template-areas属性且用.代替advert。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-areas\\s*?:\\s*?\"\\s*?header\\s*?header\\s*?header\\s*?\"\\s*?\"\\s*?.\\s*?content\\s*?content\\s*?\"\\s*?\"\\s*?footer\\s*?footer\\s*?footer\\s*?\"\\s*?;[\\s\\S]*}/gi), 'container类应该有类似于最右侧预览区的grid-template-areas属性且用.代替advert。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a94fe1369fb03452672e45d", + "title": "Place Items in Grid Areas Using the grid-area Property", + "description": [ + "像上一个挑战那样,在为网格容添加区域模板后,你可以通过添加你定义的名称将网格项放入自定义区域。为此,你需要对网格项使用grid-area:", + "
.item1 { grid-area: header; }
", + "这样,类名为item1的网格项就被放到了header区域里。这种情况下,网格项将使用整个顶行,因为这一行被名为 header 区域。", + "
", + "请使用grid-area属性,把类为item5元素放到footer区域。" + ], + "tests": [ + { + "text": "item5类应该有grid-area属性且值为footer。", + "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-area\\s*?:\\s*?footer\\s*?;[\\s\\S]*}/gi), 'item5类应该有grid-area属性且值为footer。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a90376038fddaf9a66b5d3c", - "title": "Align All Items Horizontally using justify-items", - "description": [ - "Sometimes you want all the items in your CSS Grid to share the same alignment. You can use the previously learned properties and align them individually, or you can align them all at once horizontally by using justify-items on your grid container. This property can accept all the same values you learned about in the previous two challenges, the difference being that it will move all the items in our grid to the desired alignment.", - "
", - "Use this property to center all our items horizontally." - ], - "tests": [ - { - "text": "container class should have a justify-items property that has the value of center.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*justify-items\\s*?:\\s*?center\\s*?;[\\s\\S]*}/gi), 'container class should have a justify-items property that has the value of center.');" + }, + { + "id": "5a94fe2669fb03452672e45e", + "title": "Use grid-area Without Creating an Areas Template", + "description": [ + "你在上一次挑战中学到的grid-area属性有另一种使用方式。如果网格中没有定义区域模板,你也可以像这样为它添加一个模板:", + "
item1 { grid-area: 1/1/2/4; }
", + "这里使用了你之前学习的线号来定义网格项的区域。上例中数字代表这些值:", + "
grid-area: 起始水平线 / 起始垂直线 / 末尾水平线 / 终止垂直线 ;
", + "因此,示例中的网格项将占用第 1 条和第 2 条水平线之间的行及第 1 条和第 4 条垂直线之间的列。", + "
", + "请用grid-area属性将类为item5的元素放置在第 3 条和第 4 条水平线及第 1 条和第 4 条垂直线之间的区域内。" + ], + "tests": [ + { + "text": "item5类应该有grid-area属性且值为3/1/4/4。", + "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-area\\s*?:\\s*?3\\s*?\\/\\s*?1\\s*?\\/\\s*?4\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5类应该有grid-area属性且值为3/1/4/4。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a94fe3669fb03452672e45f", + "title": "Reduce Repetition Using the repeat Function", + "description": [ + "当使用grid-template-columnsgrid-template-rows定义网格结构时,你需要为添加的每一行和每一列都输入一个值。", + "如果要添加带 100 行高度相同的网格,单独放入 100 个值不太实际。幸运的是,有一种更好的方法——使用repeat方法指定行或列的重复次数,后面加上逗号以及需要重复的值。", + "这里有一个添加 100 行网格的例子,使每行高度均为 50px:", + "
grid-template-rows: repeat(100, 50px);
", + "你还可以用 repeat 方法重复多个值,并在定义网格结构时与其他值一起使用。举个例子:", + "
grid-template-columns: repeat(2, 1fr 50px) 20px;
", + "效果相当于:", + "
grid-template-columns: 1fr 50px 1fr 50px 20px;
", + "注意:
1fr 50px重复了两次,后面跟着 20px。", + "
", + "用repeat代替grid-template-columns属性的值中的重复代码。" + ], + "tests": [ + { + "text": "container类应该有grid-template-columns属性且设置重复 3 列,宽为1fr。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?3\\s*?,\\s*?1fr\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-columns属性且设置重复 3 列,宽为1fr。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a94fdf869fb03452672e45b", - "title": "Align All Items Vertically using align-items", - "description": [ - "Using the align-items property on a grid container will set the vertical alignment for all the items in our grid.", - "
", - "Use it now to move all the items to the end of each cell." - ], - "tests": [ - { - "text": "container class should have a align-items property that has the value of end.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*align-items\\s*?:\\s*?end\\s*?;[\\s\\S]*}/gi), 'container class should have a align-items property that has the value of end.');" + }, + { + "id": "5a94fe4469fb03452672e460", + "title": "Limit Item Size Using the minmax Function", + "description": [ + "此外,内置函数minmax也可以可用于设置grid-template-columnsgrid-template-rows的值。它的作用是在网格容器改变大小时限制网格项的大小。为此,你需要指定网格项允许的尺寸范围。例如:", + "
grid-template-columns: 100px minmax(50px, 200px);
", + "在上面的代码中,grid-template-columns被设置为添加两列,第一列 100px 宽,第二列宽度最小值是 50px,最大值是 200px。", + "
", + "用minmax函数替换repeat函数中的1fr,限定其最小值为90px,最大值为1fr,你可以调整最右侧的预览面板查看效果。" + ], + "tests": [ + { + "text": "container类应该有grid-template-columns属性且设置重复 3 列,每列宽度最小值为90px,最大值为1fr。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?3\\s*?,\\s*?minmax\\s*?\\(\\s*?90px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-columns属性且设置重复 3 列,每列宽度最小值90px,最大值1fr。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a94fe5469fb03452672e461", + "title": "Create Flexible Layouts Using auto-fill", + "description": [ + "重复方法带有一个名为自动填充(auto-fill)的功能。它的功能是根据容器的大小,尽可能多地放入指定大小的行或列。你可以通过结合auto-fillminmax来更灵活地布局。", + "在最右侧的预览区中,grid-template-columns被设置为:", + "
repeat(auto-fill, minmax(60px, 1fr));
", + "上面的代码效果:列的宽度会随容器大小改变,在可以插入一个 60px 宽的列之前,当前行的所有列会一直拉伸。(译者注:动手试试你将更明白。)", + "注意:
如果容器无法使所有网格项放在同一行,余下的网格项将移至新的一行。", + "
", + "在第一个网格中,用auto-fillrepeat来填充网格,其中列宽的最小值为60px,最大值为1fr。你可以调整最右侧的预览区大小,查看自动填充效果。" + ], + "tests": [ + { + "text": "container类应该有grid-template-columns属性且使用repeatauto-fill,以便将最小宽度为60px,最大宽度为1fr的列填充至网格。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?auto-fill\\s*?,\\s*?minmax\\s*?\\(\\s*?60px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container类应该有grid-template-columns属性且使用repeatauto-fill,以便将最小宽度为60px,最大宽度为1fr的列填充至网格。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - } - }, - { - "id": "5a94fe0569fb03452672e45c", - "title": "Divide the Grid Into an Area Template", - "description": [ - "You can group cells of your grid together into an area and give the area a custom name. Do this by using grid-template-areas on the container like this:", - "
grid-template-areas:
  \"header header header\"
  \"advert content content\"
  \"footer footer footer\";
", - "The code above merges the top three cells together into an area named header, the bottom three cells into a footer area, and it makes two areas in the middle row; advert and content.", - "Note
Every word in the code represents a cell and every pair of quotation marks represent a row.", - "In addition to custom labels, you can use a period (.) to designate an empty cell in the grid.", - "
", - "Place the area template so that the cell labeled advert becomes an empty cell." - ], - "tests": [ - { - "text": "container class should have a grid-template-areas property similar to the preview but has . instead of the advert area.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-areas\\s*?:\\s*?\"\\s*?header\\s*?header\\s*?header\\s*?\"\\s*?\"\\s*?.\\s*?content\\s*?content\\s*?\"\\s*?\"\\s*?footer\\s*?footer\\s*?footer\\s*?\"\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-areas propertiy similar to the preview but has . instead of the advert area.');" + }, + { + "id": "5a94fe6269fb03452672e462", + "title": "Create Flexible Layouts Using auto-fit", + "description": [ + "auto-fit效果几乎和auto-fill一样。不同点仅在于,当容器的大小大于各网格项之和时,auto-fill将会持续地在一端放入空行或空列,这样就会使所有网格项挤到另一边;而auto-fit则不会在一端放入空行或空列,而是会将所有网格项拉伸至合适的大小。", + "注意:
如果容器无法使所有网格项放在同一行,余下的网格项将移至新的一行。", + "
", + "在第二个网格中,用auto-fitrepeat来填充网格,其中列宽的最小值为60px,最大值为1fr。你可以调整最右侧的预览区以查看差异。" + ], + "tests": [ + { + "text": "container2类应该有grid-template-columns属性,且使用repeatauto-fit以便将最小宽度为60px,最大宽度为1fr的列放入网格。", + "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?auto-fit\\s*?,\\s*?minmax\\s*?\\(\\s*?60px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container2类应该有grid-template-columns属性,且使用repeatauto-fit以便将最小宽度为60px,最大宽度为1fr的列放入网格。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
", + "
", + "
1
", + "
2
", + "
3
", + "
4
", + "
5
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe1369fb03452672e45d", - "title": "Place Items in Grid Areas Using the grid-area Property", - "description": [ - "After creating an areas template for your grid container, as shown in the previous challenge, you can place an item in your custom area by referencing the name you gave it. To do this, you use the grid-area property on an item like this:", - "
.item1 { grid-area: header; }
", - "This lets the grid know that you want the item1 class to go in the area named header. In this case, the item will use the entire top row because that whole row is named as the header area.", - "
", - "Place an element with the item5 class in the footer area using the grid-area property." - ], - "tests": [ - { - "text": "item5 class should have a grid-area property that has the value of footer.", - "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-area\\s*?:\\s*?footer\\s*?;[\\s\\S]*}/gi), 'item5 class should have a grid-area property that has the value of footer.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe2669fb03452672e45e", - "title": "Use grid-area Without Creating an Areas Template", - "description": [ - "The grid-area property you learned in the last challenge can be used in another way. If your grid doesn't have an areas template to reference, you can create an area on the fly for an item to be placed like this:", - "
item1 { grid-area: 1/1/2/4; }
", - "This is using the line numbers you learned about earlier to define where the area for this item will be. The numbers in the example above represent these values:", - "
grid-area: horizontal line to start at / vertical line to start at / horizontal line to end at / vertical line to end at;
", - "So the item in the example will consume the rows between lines 1 and 2, and the columns between lines 1 and 4.", - "
", - "Using the grid-area property, place the element with item5 class between the third and fourth horizontal lines and between the first and fourth vertical lines." - ], - "tests": [ - { - "text": "item5 class should have a grid-area property that has the value of 3/1/4/4.", - "testString": "assert(code.match(/.item5\\s*?{[\\s\\S]*grid-area\\s*?:\\s*?3\\s*?\\/\\s*?1\\s*?\\/\\s*?4\\s*?\\/\\s*?4\\s*?;[\\s\\S]*}/gi), 'item5 class should have a grid-area property that has the value of 3/1/4/4.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe3669fb03452672e45f", - "title": "Reduce Repetition Using the repeat Function", - "description": [ - "When you used grid-template-columns and grid-template-rows to define the structure of a grid, you entered a value for each row or column you created.", - "Lets say you want a grid with 100 rows of the same height. It isn't very practical to insert 100 values individually. Fortunately, there's a better way - by using the repeat function to specify the number of times you want your column or row to be repeated, followed by a comma and the value you want to repeat.", - "Here's an example that would create the 100 row grid, each row at 50px tall.", - "
grid-template-rows: repeat(100, 50px);
", - "You can also repeat multiple values with the repeat function, and insert the function amongst other values when defining a grid structure. Here's what I mean:", - "
grid-template-columns: repeat(2, 1fr 50px) 20px;
", - "This translates to:", - "
grid-template-columns: 1fr 50px 1fr 50px 20px;
", - "Note
1fr 50px is repeated twice followed by 20px.", - "
", - "Use repeat to remove repetition from the grid-template-columns property." - ], - "tests": [ - { - "text": "container class should have a grid-template-columns property that is set to repeat 3 columns with the width of 1fr.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?3\\s*?,\\s*?1fr\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-columns property that is set to repeat 3 columns with the width of 1fr.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe4469fb03452672e460", - "title": "Limit Item Size Using the minmax Function", - "description": [ - "There's another built-in function to use with grid-template-columns and grid-template-rows called minmax. It's used to limit the size of items when the grid container changes size. To do this you need to specify the acceptable size range for your item. Here is an example:", - "
grid-template-columns: 100px minmax(50px, 200px);
", - "In the code above, grid-template-columns is set to create two columns; the first is 100px wide, and the second has the minimum width of 50px and the maximum width of 200px.", - "
", - "Using the minmax function, replace the 1fr in the repeat function with a column size that has the minimum width of 90px and the maximum width of 1fr, and resize the preview panel to see the effect." - ], - "tests": [ - { - "text": "container class should have a grid-template-columns property that is set to repeat 3 columns with the minimum width of 90px and maximum width of 1fr.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?3\\s*?,\\s*?minmax\\s*?\\(\\s*?90px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-columns property that is set to repeat 3 columns with the minimum width of 90px and maximum width of 1fr.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe5469fb03452672e461", - "title": "Create Flexible Layouts Using auto-fill", - "description": [ - "The repeat function comes with a option called auto-fill. This allows you to automatically insert as many rows or columns of your desired size as possible depending on the size of the container. You can create flexible layouts when combining auto-fill with minmax.", - "In the preview, grid-template-columns is set to", - "
repeat(auto-fill, minmax(60px, 1fr));
", - "When the container changes size, this setup keeps inserting 60px columns and stretching them until it can insert another one.", - "Note
If your container can't fit all your items on one row, it will move them down to a new one.", - "
", - "In the first grid, use auto-fill with repeat to fill the grid with columns that have a minimum width of 60px and maximum of 1fr. Then resize the preview to see auto-fill in action." - ], - "tests": [ - { - "text": "container class should have a grid-template-columns property with repeat and auto-fill that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?auto-fill\\s*?,\\s*?minmax\\s*?\\(\\s*?60px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container class should have a grid-template-columns property with repeat and auto-fill that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe6269fb03452672e462", - "title": "Create Flexible Layouts Using auto-fit", - "description": [ - "auto-fit works almost identically to auto-fill. The only difference is that when the container's size exceeds the size of all the items combined, auto-fill keeps inserting empty rows or columns and pushes your items to the side, while auto-fit collapses those empty rows or columns and stretches your items to fit the size of the container.", - "Note
If your container can't fit all your items on one row, it will move them down to a new one.", - "
", - "In the second grid, use auto-fit with repeat to fill the grid with columns that have a minimum width of 60px and maximum of 1fr. Then resize the preview to see the difference." - ], - "tests": [ - { - "text": "container2 class should have a grid-template-columns property with repeat and auto-fit that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.", - "testString": "assert(code.match(/.container\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?repeat\\s*?\\(\\s*?auto-fit\\s*?,\\s*?minmax\\s*?\\(\\s*?60px\\s*?,\\s*?1fr\\s*?\\)\\s*?\\)\\s*?;[\\s\\S]*}/gi), 'container2 class should have a grid-template-columns property with repeat and auto-fit that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
", - "
", - "
1
", - "
2
", - "
3
", - "
4
", - "
5
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe7769fb03452672e463", - "title": "Use Media Queries to Create Responsive Layouts", - "description": [ - "CSS Grid can be an easy way to make your site more responsive by using media queries to rearrange grid areas, change dimensions of a grid, and rearrange the placement of items.", - "In the preview, when the viewport width is 300px or more, the number of columns changes from 1 to 2. The advertisement area then occupies the left column completely.", - "
", - "When the viewport width is 400px or more, make the header area occupy the top row completely and the footer area occupy the bottom row completely." - ], - "tests": [ - { - "text": "When the viewport is 400px or more, container class should have a grid-template-areas property in which the footer and header areas occupy the top and bottom rows respectively and advert and content occupy the left and right columns of the middle row.", - "testString": "assert(code.match(/@media\\s*?\\(\\s*?min-width\\s*?:\\s*?400px\\s*?\\)[\\s\\S]*.container\\s*?{[\\s\\S]*grid-template-areas\\s*?:\\s*?\"\\s*?header\\s*?header\\s*?\"\\s*?\"\\s*?advert\\s*?content\\s*?\"\\s*?\"\\s*?footer\\s*?footer\\s*?\"\\s*?;[\\s\\S]*}/gi), 'When the viewport is 400px or more, container class should have a grid-template-areas property in which the footer and header areas occupy the top and bottom rows respectively and advert and content occupy the left and right columns of the middle row.');" - } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
header
", - "
advert
", - "
content
", - "
footer
", - "
" - ], - "head": [], - "tail": [] - } - } - }, - { - "id": "5a94fe8569fb03452672e464", - "title": "Create Grids within Grids", - "description": [ - "Turning an element into a grid only affects the behavior of its direct descendants. So by turning a direct descendant into a grid, you have a grid within a grid.", - "For example, by setting the display and grid-template-columns properties of the element with the item3 class, you create a grid within your grid.", - "
", - "Turn the element with the item3 class into a grid with two columns with a width of auto and 1fr using display and grid-template-columns." - ], - "tests": [ - { - "text": "item3 class should have a grid-template-columns property with auto and 1fr as values.", - "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?auto\\s*?1fr\\s*?;[\\s\\S]*}/gi), 'item3 class should have a grid-template-columns property with auto and 1fr as values.');" - }, - { - "text": "item3 class should have a display property with the value of grid.", - "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*display\\s*?:\\s*?grid\\s*?;[\\s\\S]*}/gi), 'item3 class should have a display property with the value of grid.');" + }, + { + "id": "5a94fe7769fb03452672e463", + "title": "Use Media Queries to Create Responsive Layouts", + "description": [ + "通过使用媒体查询重新排列网格区域,更改网格尺寸以及重新排列网格项位置,CSS 网格能轻松地使网站更具响应性。", + "在最右侧的预览区中,当网页可视区域的宽不小于 300px 时,列数从 1 变为 2。并且,广告(advertisement)区域完全占据左列。", + "
", + "当网页可视区域的宽不小于400px时,使 header 区域完全占据最顶行,footer 区域完全占据最底行。" + ], + "tests": [ + { + "text": "当网页可视区域的宽在400px及以上时,container类应该有grid-template-areas属性且使得 footer 和 header 区域分别占据顶行和底行,advert 和 content 区域分别占据中间行的左和右列。", + "testString": "assert(code.match(/@media\\s*?\\(\\s*?min-width\\s*?:\\s*?400px\\s*?\\)[\\s\\S]*.container\\s*?{[\\s\\S]*grid-template-areas\\s*?:\\s*?\"\\s*?header\\s*?header\\s*?\"\\s*?\"\\s*?advert\\s*?content\\s*?\"\\s*?\"\\s*?footer\\s*?footer\\s*?\"\\s*?;[\\s\\S]*}/gi), '当网页可视区域的宽在400px及以上时,container类应该有grid-template-areas属性且使得 footer 和 header 区域分别占据顶行和底行,advert 和 content 区域分别占据中间行的左和右列。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
header
", + "
advert
", + "
content
", + "
footer
", + "
" + ], + "head": [], + "tail": [] + } } - ], - "solutions": [], - "hints": [], - "releasedOn": "", - "challengeType": 0, - "files": { - "indexhtml": { - "key": "indexhtml", - "ext": "html", - "name": "index", - "contents": [ - "", - " ", - "
", - "
header
", - "
advert
", - "
", - "
paragraph1
", - "
paragraph2
", - "
", - "
footer
", - "
" - ], - "head": [], - "tail": [] + }, + { + "id": "5a94fe8569fb03452672e464", + "title": "Create Grids within Grids", + "description": [ + "将元素转换为网格只会影响其子代元素。因此,在把某个子代元素设置为网格后,就会得到一个嵌套的网格。", + "例如,设置类为item3的元素的displaygrid-template-columns属性,就会得到一个嵌套的网格。", + "
", + "用displaygrid-template-columns,使类为item3元素转换为有两列且宽度为auto1fr的网格。" + ], + "tests": [ + { + "text": "item3类应该有grid-template-columns属性且值为auto1fr。", + "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*grid-template-columns\\s*?:\\s*?auto\\s*?1fr\\s*?;[\\s\\S]*}/gi), 'item3类应该有grid-template-columns属性且将auto1fr作为值。');" + }, + { + "text": "item3类有display属性且值为grid。", + "testString": "assert(code.match(/.item3\\s*?{[\\s\\S]*display\\s*?:\\s*?grid\\s*?;[\\s\\S]*}/gi), 'item3类有display属性且值为grid。');" + } + ], + "solutions": [], + "hints": [], + "releasedOn": "", + "challengeType": 0, + "files": { + "indexhtml": { + "key": "indexhtml", + "ext": "html", + "name": "index", + "contents": [ + "", + " ", + "
", + "
header
", + "
advert
", + "
", + "
paragraph1
", + "
paragraph2
", + "
", + "
footer
", + "
" + ], + "head": [], + "tail": [] + } } } - } - ] -} \ No newline at end of file + ] + } \ No newline at end of file diff --git a/01-responsive-web-design/css-grid.md b/01-responsive-web-design/css-grid.md new file mode 100644 index 0000000..6c9e035 --- /dev/null +++ b/01-responsive-web-design/css-grid.md @@ -0,0 +1,3 @@ +# CSS 网格简介 # + +CSS 网格帮助你轻松实现复杂的 Web 设计。它通过把 HTML 元素转换为具有行和列的网格容器,以便将子元素放置在所需要的位置。 \ No newline at end of file diff --git a/01-responsive-web-design/responsive-web-design-principles.json b/01-responsive-web-design/responsive-web-design-principles.json index 9f2ecf0..a8a76b8 100644 --- a/01-responsive-web-design/responsive-web-design-principles.json +++ b/01-responsive-web-design/responsive-web-design-principles.json @@ -8,24 +8,24 @@ "id": "587d78b0367417b2b2512b08", "title": "Create a Media Query", "description": [ - "Media Queries are a new technique introduced in CSS3 that change the presentation of content based on different viewport sizes. The viewport is a user's visible area of a web page, and is different depending on the device used to access the site.", - "Media Queries consist of a media type, and if that media type matches the type of device the document is displayed on, the styles are applied. You can have as many selectors and styles inside your media query as you want.", - "Here's an example of a media query that returns the content when the device's width is less than or equal to 100px:", + "媒体查询是 CSS3 中引入的一项新技术,它可以根据不同的可视窗口大小显示不同的布局。可视窗口是用户在网页上的可见区域,根据访问网站的设备不同而不同。", + "媒体查询由媒体类型组成,如果媒体类型与展示网页的设备类型匹配,则应用对应的样式。你可以在媒体查询中用上你想用的选择器和样式。", + "下面是一个媒体查询的例子,当设备宽度小于或等于 100px 时返回内容:", "@media (max-width: 100px) { /* CSS Rules */ }", - "and the following media query returns the content when the device's height is more than or equal to 350px:", + "以下定义的媒体查询,是当设备高度大于或等于 350px 时返回内容:", "@media (min-height: 350px) { /* CSS Rules */ }", - "Remember, the CSS inside the media query is applied only if the media type matches that of the device being used.", + "只有当媒体类型与当前设备匹配时,才应用媒体查询中的 CSS。", "
", - "Add a media query, so that the p tag has a font-size of 10px when the device's height is less than or equal to 800px." + "增加一个设备的高度小于或等于 800px 时,p 标签的 font-size 为 10px 的媒体查询。" ], "tests": [ { - "text": "Your p element should have the font-size of 10px when the device height is less than or equal to 800px.", - "testString": "assert($('p').css('font-size') == '10px', 'Your p element should have the font-size of 10px when the device height is less than or equal to 800px.');" + "text": "当设备 height 小于或等于 800px 时,p 元素 font-size 应为 10px。", + "testString": "assert($('p').css('font-size') == '10px', '当设备 height 小于或等于 800px 时,p 元素 font-size 应为 10px。');" }, { - "text": "Declare a @media query for devices with a height less than or equal to 800px.", - "testString": "assert(code.match(/@media\\s?\\(max-height:\\s*?800px\\)/g), 'Declare a @media query for devices with a height less than or equal to 800px.');" + "text": "使用 @mediaheight 小于或等于 800px 的设备添加一个媒体查询。", + "testString": "assert(code.match(/@media\\s?\\(max-height:\\s*?800px\\)/g), '使用 @mediaheight 小于或等于 800px 的设备添加一个媒体查询。');" } ], "releasedOn": "Feb 17, 2017", @@ -58,26 +58,26 @@ "id": "587d78b1367417b2b2512b09", "title": "Make an Image Responsive", "description": [ - "Making images responsive with CSS is actually very simple. Instead of applying an absolute width to an element:", + "用 CSS 来让图片自适应其实很简单。不要使用绝对单位:", "img { width: 720px; }", - "You can use:", + "你应该使用:", "
img {
  max-width: 100%;
  display: block;
  height: auto;
}
", - "The max-width property of 100% scales the image to fit the width of its container, but the image won't stretch wider than its original width. Setting the display property to block changes the image from an inline element (its default), to a block element on its own line. The height property of auto keeps the original aspect ratio of the image.", + "max-width 属性能让图片以 100% 的最大宽度适应其父容器的宽度,但图片不会拉伸得比原始宽度还宽。将 display 属性设置为 block 可以让 image 标签从内联元素(默认值)更改为块级元素。设置 height 属性为 auto 保持图片的原始宽高比。", "
", - "Add style rules for the img tag to make it responsive to the size of its container. It should display as a block-level element, it should fit the full width of its container without stretching, and it should keep its original aspect ratio." + "给 img 标签增加样式规则使它自适应容器尺寸。应声明为块级元素,应适应它容器的宽度,应保持原本的宽高比。" ], "tests": [ { - "text": "Your img tag should have a max-width set to 100%.", - "testString": "assert(code.match(/max-width:\\s*?100%;/g), 'Your img tag should have a max-width set to 100%.');" + "text": "img 标签应设置 max-width 为 100%。", + "testString": "assert(code.match(/max-width:\\s*?100%;/g), 'img 标签应设置 max-width 为 100%。');" }, { - "text": "Your img tag should have a display set to block.", - "testString": "assert($('img').css('display') == 'block', 'Your img tag should have a display set to block.');" + "text": "img 标签应设置 display 为 block。", + "testString": "assert($('img').css('display') == 'block', 'img 标签应设置 display 为 block。');" }, { - "text": "Your img tag should have a height set to auto.", - "testString": "assert(code.match(/height:\\s*?auto;/g), 'Your img tag should have a height set to auto.');" + "text": "img 标签应设置 height 为 auto。", + "testString": "assert(code.match(/height:\\s*?auto;/g), 'img 标签应设置 height 为 auto。');" } ], "releasedOn": "Feb 17, 2017", @@ -105,20 +105,20 @@ "id": "587d78b1367417b2b2512b0a", "title": "Use a Retina Image for Higher Resolution Displays", "description": [ - "The simplest way to make your images appear \"retina\" (and optimize them for retina displays) is to define their width and height values as only half of what the original file is.", - "Here is an example of an image that is only using half of the original height and width:", - "
<style>
  img { height: 250px; width: 250px; }
</style>
<img src="coolPic500x500" alt="A most excellent picture">
", + "为优化图片在高分辨率设备下的显示效果,最简单的方式是定义它们的 widthheight 值为源文件宽高的一半。", + "这是一个图片宽高设置为源文件一半的例子:", + "
<style>
  img { height: 250px; width: 250px; }
</style>
<img src="coolPic500x500" alt="一张高质量的图片">
", "
", - "Set the width and height of the img tag to half of their original values. In this case, both the original height and the original width are 200px." + "设置 img 标签的 widthheight 为它们原始宽高的一半。在这个例子中,原始 height 和原始 width 的值都为 200px。" ], "tests": [ { - "text": "Your img tag should have a width of 100 pixels.", - "testString": "assert($('img').css('width') == '100px', 'Your img tag should have a width of 100 pixels.');" + "text": "img 标签的 width 值应为 100px。", + "testString": "assert($('img').css('width') == '100px', 'img 标签的 width 值应为 100px。');" }, { - "text": "Your img tag should have a height of 100 pixels.", - "testString": "assert($('img').css('height') == '100px', 'Your img tag should have a height of 100 pixels.');" + "text": "img 标签应含有 100px 的 height。", + "testString": "assert($('img').css('height') == '100px', 'img 标签应含有 100px 的 height。');" } ], "releasedOn": "Feb 17, 2017", @@ -146,20 +146,20 @@ "id": "587d78b1367417b2b2512b0c", "title": "Make Typography Responsive", "description": [ - "Instead of using em or px to size text, you can use viewport units for responsive typography. Viewport units, like percentages, are relative units, but they are based off different items. Viewport units are relative to the viewport dimensions (width or height) of a device, and percentages are relative to the size of the parent container element.", - "The four different viewport units are:", - "
  • vw: 10vw would be 10% of the viewport's width.
  • vh: 3vh would be 3% of the viewport's height.
  • vmin: 70vmin would be 70% of the viewport's smaller dimension (height vs. width).
  • vmax: 100vmax would be 100% of the viewport's bigger dimension (height vs. width).
", + "除了用 empx 去设置文本大小, 你还可以用视窗单位来做响应式排版。视窗单位还有百分比,它们都是相对单位,但却基于不同的参照物。视窗单位相对于设备的视窗尺寸 (宽度或高度) ,百分比是相对于父级元素的大小。", + "四个不同的视窗单位分别是:", + "
  • vw:如 10vw 的意思是视窗宽度的 10%。
  • vh:3vh 的意思是视窗高度的 3%。
  • vmin:70vmin 的意思是视窗中较小尺寸的 70% (高度 VS 宽度)。
  • vmax:100vmax 的意思是视窗中较大尺寸的 100% (高度 VS 宽度)。
", "
", - "Set the width of the h2 tag to 80% of the viewport's width and the width of the paragraph as 75% of the viewport's smaller dimension." + "设置 h2 标签 width 为视窗宽度的 80%,并且段落 width 为视窗高度和宽度中较小值的 70%。" ], "tests": [ { - "text": "Your h2 tag should have a width of 80vw.", - "testString": "assert(code.match(/h2\\s*?{\\s*?width:\\s*?80vw;\\s*?}/g), 'Your h2 tag should have a width of 80vw.');" + "text": "h2 标签 width 应为 80vw。", + "testString": "assert(code.match(/h2\\s*?{\\s*?width:\\s*?80vw;\\s*?}/g), 'h2 标签的 width 应为 80vw。');" }, { - "text": "Your p tag should have a width of 75vmin.", - "testString": "assert(code.match(/p\\s*?{\\s*?width:\\s*?75vmin;\\s*?}/g), 'Your p tag should have a width of 75vmin.');" + "text": "p 标签 width 应为 75vmin。", + "testString": "assert(code.match(/p\\s*?{\\s*?width:\\s*?75vmin;\\s*?}/g), 'p 标签的 width 应为 75vmin。');" } ], "releasedOn": "Feb 17, 2017", diff --git a/01-responsive-web-design/responsive-web-design-principles.md b/01-responsive-web-design/responsive-web-design-principles.md new file mode 100644 index 0000000..08812dd --- /dev/null +++ b/01-responsive-web-design/responsive-web-design-principles.md @@ -0,0 +1 @@ +如今,从大屏的台式电脑到小屏的手机,我们有各式各样的设备可以上网。这些设备有着不同的屏幕尺寸、分辨率和处理能力。响应式 Web 设计是一种能自如响应不同尺寸设备的设计方法。能使页面结构和 CSS 规则能够灵活应用于不同设备之间的差异。一般来说,页面的 CSS 是设计给目标用户看的。如果你预计网站的大部分流量来自移动端,那么应该采取“移动端优先”的策略,再为 PC 端做兼容。如果你预计网站的大部分流量来自 PC 端,那么应该采取“PC 端优先”的策略,再为移动端做兼容。CSS 提供了书写不同样式规则的工具,然后根据显示网页的设备应用它们。本节将介绍使用 CSS 来响应 Web 设计的基本方法。 diff --git a/01-responsive-web-design/responsive-web-design-projects.json b/01-responsive-web-design/responsive-web-design-projects.json index da24157..9636a99 100644 --- a/01-responsive-web-design/responsive-web-design-projects.json +++ b/01-responsive-web-design/responsive-web-design-projects.json @@ -8,21 +8,21 @@ "id": "bd7158d8c442eddfaeb5bd18", "title": "Build a Tribute Page", "description": [ - "Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/zNqgVx.", - "Fulfill the below user stories and get all of the tests to pass. Give it your own personal style.", - "You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!", - "User Story #1: My tribute page should have an element with a corresponding id=\"main\", which contains all other elements.", - "User Story #2: I should see an element with a corresponding id=\"title\", which contains a string (i.e. text) that describes the subject of the tribute page (e.g. \"Dr. Norman Borlaug\").", - "User Story #3: I should see a div element with a corresponding id=\"img-div\".", - "User Story #4: Within the img-div element, I should see an img element with a corresponding id=\"image\".", - "User Story #5: Within the img-div element, I should see an element with a corresponding id=\"img-caption\" that contains textual content describing the image shown in img-div.", - "User Story #6: I should see an element with a corresponding id=\"tribute-info\", which contains textual content describing the subject of the tribute page.", - "User Story #7: I should see an a element with a corresponding id=\"tribute-link\", which links to an outside site that contains additional information about the subject of the tribute page. HINT: You must give your element an attribute of target and set it to _blank in order for your link to open in a new tab (i.e. target=\"_blank\").", - "User Story #8: The img element should responsively resize, relative to the width of its parent element, without exceeding its original size.", - "User Story #9: The img element should be centered within its parent element.", - "You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js.", - "Once you're done, submit the URL to your working project with all its tests passing.", - "Remember to use the Read-Search-Ask method if you get stuck." + "目标:使用 CodePen.io 搭建一个与这个功能上相似的 app:https://codepen.io/freeCodeCamp/full/zNqgVx。", + "在满足以下 用户故事 并能通过所有测试的前提下,你可以根据自己的喜好来美化你的 app。", + "你可以使用 HTML、JavaScript 以及 CSS 来完成项目,由于目前我们只学到了 CSS,因此建议你只使用 CSS 完成这个项目,顺便还可以巩固一下之前学到的内容。你也可以使用 Bootstrap 或者是 SASS。在当前的项目中,不推荐使用其他技术如 jQurey、React、Angular 或者是 Vue,因为一旦出现问题,风险自担。但在别的项目中我们仍有机会去使用不同的技术栈比如 React,我们会接受并尽力处理你在使用建议的技术栈过程中遇到的问题,编码愉快!", + "用户故事 #1:我的致敬页应有对应 id=\"main\" 的元素, 其中包含其他的所有元素", + "用户故事 #2:我应该看到一个具有相应 id=\"title\" 的元素,其中包含描述致敬页主题的字符串 (即文本),如 \"Dr. Norman Borlaug\"。", + "用户故事 #3:我应该看到一个带有对应 id=\"img-div\"div 元素。", + "用户故事 #4:img-div 元素内,我应该看见有对应 id=\"image\"img 元素", + "用户故事 #5:img-div 元素内,我应该看见一个具有相应 id=\"img-caption\" 的元素,其中包含对 img-div 中图像的描述。", + "用户故事 #6:我应该看见具有对应 id=\"tribute-info\" 的元素,其中包含描述致敬页主题的文本内容", + "用户故事 #7:我应该看见具有对应 id=\"tribute-link\" 的元素,它链接到一个包含有关致敬页主题额外信息的外部网页,提示: 你必须为元素提供 target 属性,并设置为 _blank 以便在新选项卡中打开连接 (例 target=\"_blank\")。", + "用户故事 #8:img 元素应相对于其父元素的宽度响应地调整大小,但不超过其原始大小。", + "用户故事 #9:img 在其父元素内居中。", + "你可以通过 fork 此 CodePen 来构建项目,或者你可以使用此 CDN 链接在你喜欢的任何环境中运行测试:https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js。", + "完成项目并通过所有测试后, 输入你的项目在 CodePen 上的链接", + "要是卡住的话,记得使用 Read-Search-Ask。" ], "releasedOn": "January 1, 2016", "tests": [], @@ -33,28 +33,28 @@ "id": "587d78af367417b2b2512b03", "title": "Build a Survey Form", "description": [ - "Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/VPaoNP.", - "Fulfill the below user stories and get all of the tests to pass. Give it your own personal style.", - "You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!", - "User Story #1: I can see a title with id=\"title\" in H1 sized text.", - "User Story #2: I can see a short explanation with id=\"description\" in P sized text.", - "User Story #3: I can see a form with id=\"survey-form\".", - "User Story #4: Inside the form element, I am required to enter my name in a field with id=\"name\".", - "User Story #5: Inside the form element, I am required to enter an email in a field with id=\"email\".", - "User Story #6: If I enter an email that is not formatted correctly, I will see an HTML5 validation error.", - "User Story #7: Inside the form, I can enter a number in a field with id=\"number\".", - "User Story #8: If I enter non-numbers in the number input, I will see an HTML5 validation error.", - "User Story #9: If I enter numbers outside the range of the number input, which are defined by the min and max attributes, I will see an HTML5 validation error.", - "User Story #10: For the name, email, and number input fields inside the form I can see corresponding labels that describe the purpose of each field with the following ids: id=\"name-label\", id=\"email-label\", and id=\"number-label\".", - "User Story #11: For the name, email, and number input fields, I can see placeholder text that gives me a description or instructions for each field.", - "User Story #12: Inside the form element, I can select an option from a dropdown that has a corresponding id=\"dropdown\".", - "User Story #13: Inside the form element, I can select a field from one or more groups of radio buttons. Each group should be grouped using the name attribute.", - "User Story #14: Inside the form element, I can select several fields from a series of checkboxes, each of which must have a value attribute.", - "User Story #15: Inside the form element, I am presented with a textarea at the end for additional comments.", - "User Story #16: Inside the form element, I am presented with a button with id=\"submit\" to submit all my inputs.", - "You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js", - "Once you're done, submit the URL to your working project with all its tests passing.", - "Remember to use the Read-Search-Ask method if you get stuck." + "目标:使用CodePen.iohttps://codepen.io/freeCodeCamp/full/VPaoNP。", + "在满足以下 user stories 并能通过所有测试的前提下,你可以根据自己的喜好来美化你的 app。", + "你可以使用 HTML、JavaScript 以及 CSS 来完成项目,由于目前我们只学到了 CSS,因此建议你只使用 CSS 完成这个项目,顺便还可以巩固一下之前学到的内容。你也可以使用 Bootstrap 或者是 SASS。在当前的项目中,不推荐使用其他技术如 jQurey、React、Angular 或者是 Vue,因为一旦出现问题,风险自担。但在别的项目中我们仍有机会去使用不同的技术栈比如 React,我们会接受并尽力处理你在使用建议的技术栈过程中遇到的问题,编码愉快!", + "用户故事 #1:我能看见一个 H1 大小 id=\"title\" 的标题。", + "用户故事 #1:我能看见一个 P 大小 id=\"description\" 的简述文字。", + "用户故事 #3:我能看见一个 id=\"survey-form\"form。", + "用户故事 #4:在 form 元素内, 我需要在 id=\"name\" 的字段中输入我的名字。", + "用户故事 #5:在 form 元素内, 我需要在 id=\"email\" 的字段中输入邮箱。", + "用户故事 #6:如果我输入了格式不正确的邮箱,我将会看见验证错误信息。", + "用户故事 #7:id=\"number\" 的字段中输入数字。", + "用户故事 #8:如果我在数字输入框内输入非数字,我将会看见验证错误信息。", + "用户故事 #9:如果我输入的数字超出了范围(使用 minmax 属性定义),我将会看见验证错误信息。", + "用户故事 #10:对于表单中的名称,邮箱和数字输入框应该使用对应 id 为:id=\"name-label\", id=\"email-label\", 和 id=\"number-label\" 的描述标签", + "用户故事 #11:在表单中的名称,邮箱和数字输入框中,我能看到各自的描述文字作为占位符。", + "用户故事 #12:在表单元素内,我可以在 id=\"dropdown\" 的下拉列表中选择一个选项。", + "用户故事 #13:在表单元素内,我可以从一组或多组单选按钮中选择一个字段。每组使用 name 属性进行分组。", + "用户故事 #14:在表单元素内,我可以从一系列复选框中选择几个字段,每个复选框都必须具有 value 属性。", + "用户故事 #15:在表单元素内,我能看见在最后有个 textarea 用于附加注释。", + "用户故事 #16:在表单元素内,我能看见一个 id=\"submit\" 的按钮,用于提交我所有的输入。", + "你可以通过 fork 此 this CodePen pen 来构建项目,或者你可以使用此 CDN 链接在你喜欢的任何环境中运行测试:https://gitcdn.link/repo/freeCodeCamp/testable-projects-fcc/master/build/bundle.js。", + "完成项目并通过所有测试后, 输入你的项目在 CodePen 上的链接。", + "要是卡住的话,记得使用 Read-Search-Ask。" ], "releasedOn": "January 15, 2017", "tests": [], @@ -150,4 +150,4 @@ "challengeType": 3 } ] -} \ No newline at end of file +} diff --git a/01-responsive-web-design/responsive-web-design-projects.md b/01-responsive-web-design/responsive-web-design-projects.md new file mode 100644 index 0000000..9c035e6 --- /dev/null +++ b/01-responsive-web-design/responsive-web-design-projects.md @@ -0,0 +1,13 @@ +# Introduction to the Responsive Web Design Projects # + +Time to put your newly learnt skills to work! By working on projects you would have the opportunity of applying all the skills, principles and concepts you have learnt so far HTML, CSS, Visual Design, Accessibility, etc. + +In this section you get the chance to: + +* Build a Tribute Page +* Build a Survey Form +* Build a Product Landing Page +* Build a Technical Documentation Page +* Build a Personal Portfolio Webpage + + diff --git a/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting.md b/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting.md new file mode 100644 index 0000000..420ffed --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting.md @@ -0,0 +1,11 @@ +# Introduction to Basic Algorithm Scripting # + +A computer algorithm is a sequence of steps that is followed to achieve a particular outcome. To write an algorithm, you must first understand a problem, and then solve it with coding. + +To make solving problems eaiser, it can be helpful to break them down into many chuncks. Then, each chunk can be solved one by one. For example, if you are building a calculator, don't try to solve the problem as a whole. First, consider how to get inputs. Then, determine each arithematic operation one by one. Finally, display the results. + +In this section we will learn to solve basic algorithm problems using JavaScript. This will help you improve your problem solving skills and prepare you to later solve more complex problems. + +## Hint ## + +If you get stuck, try using console.log() to log variable values to the console. This will help to debug problems. diff --git a/02-javascript-algorithms-and-data-structures/basic-data-structures.md b/02-javascript-algorithms-and-data-structures/basic-data-structures.md new file mode 100644 index 0000000..7d1d651 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/basic-data-structures.md @@ -0,0 +1,3 @@ +# Introduction to the Basic Data Structure Challenges # + +Data can be stored and accessed in many different ways, both in Javascript and other languages. This section will teach you how to manipulate arrays, as well as access and copy the information within them. It will also teach you how to manipulate and access the data within Javascript objects, using both dot and bracket notation. When you're done with this section, you should understand the basic properties and differences between arrays and objects, as well as how to choose which to use for a given purpose. diff --git a/02-javascript-algorithms-and-data-structures/basic-javascript.md b/02-javascript-algorithms-and-data-structures/basic-javascript.md new file mode 100644 index 0000000..1b46fe2 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/basic-javascript.md @@ -0,0 +1,3 @@ +# Introduction to JavaScript # + +JavaScript is a high-level programming language that all modern web browsers support. It is also one of the core technologies of the web, along with HTML and CSS that you may have learned previously. This section will cover basic JavaScript programming concepts, which range from variables and arithmetic to objects and loops. diff --git a/02-javascript-algorithms-and-data-structures/debugging.md b/02-javascript-algorithms-and-data-structures/debugging.md new file mode 100644 index 0000000..b4375fb --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/debugging.md @@ -0,0 +1,41 @@ +# Introduction to the Debugging Challenges # + +Debugging is a valuable and (unfortunately) necessary tool for programmers. It follows the testing phase of checking if your code works as intended, and discovering it does not. Debugging is the process of finding exactly what isn't working and fixing it. After spending time creating a brilliant block of code, it is tough realizing it may have errors. These issues generally come in three forms: 1) syntax errors that prevent a program from running, 2) runtime errors when code fails to execute or has unexpected behavior, and 3) semantic (or logical) errors when code doesn't do what it's meant to. + +Modern code editors (and experience) can help identify syntax errors. Semantic and runtime errors are harder to find. They may cause your program to crash, make it run forever, or give incorrect output. Think of debugging as trying to understand why your code is behaving the way it is. + +Example of a syntax error - often detected by the code editor: + +``` +funtion willNotWork( { + console.log("Yuck"); +} +// "function" keyword is misspelled and there's a missing parenthesis +``` + +Here's an example of a runtime error - often detected while the program executes: + +``` +function loopy() { + while(true) { + console.log("Hello, world!"); + } +} +// Calling loopy starts an infinite loop, which may crash your browser +``` + +Example of a semantic error - often detected after testing code output: + +``` +function calcAreaOfRect(w, h) { + return w + h; // This should be w * h +} +let myRectArea = calcAreaOfRect(2, 3); +// Correct syntax and the program executes, but this gives the wrong answer +``` + +Debugging is frustrating, but it helps to develop (and follow) a step-by-step approach to review your code. This means checking the intermediate values and types of variables to see if they are what they should be. You can start with a simple process of elimination. + +For example, if function A works and returns what it's supposed to, then function B may have the issue. Or start checking values in a block of code from the middle to try to cut the search space in half. A problem in one spot indicates a bug in the first half of the code. If not, it's likely in the second. + +This section will cover a couple helpful tools to find bugs, and some of the common forms they take. Fortunately, debugging is a learnable skill that just requires a little patience and practice to master. \ No newline at end of file diff --git a/02-javascript-algorithms-and-data-structures/es6.json b/02-javascript-algorithms-and-data-structures/es6.json index 75464f1..cd1ad71 100644 --- a/02-javascript-algorithms-and-data-structures/es6.json +++ b/02-javascript-algorithms-and-data-structures/es6.json @@ -8,33 +8,33 @@ "id": "587d7b87367417b2b2512b3f", "title": "Explore Differences Between the var and let Keywords", "description": [ - "One of the biggest problems with declaring variables with the var keyword is that you can overwrite variable declarations without an error.", - "
var camper = 'James';
var camper = 'David';
console.log(camper);
// logs 'David'
", - "As you can see in the code above, the camper variable is originally declared as James and then overridden to be David.", - "In a small application, you might not run into this type of problem, but when your code becomes larger, you might accidentally overwrite a variable that you did not intend to overwrite.", - "Because this behavior does not throw an error, searching and fixing bugs becomes more difficult.
", - "A new keyword called let was introduced in ES6 to solve this potential issue with the var keyword.", - "If you were to replace var with let in the variable declarations of the code above, the result would be an error.", - "
let camper = 'James';
let camper = 'David'; // throws an error
", - "This error can be seen in the console of your browser.", - "So unlike var, when using let, a variable with the same name can only be declared once.", - "Note the \"use strict\". This enables Strict Mode, which catches common coding mistakes and \"unsafe\" actions. For instance:", - "
\"use strict\";
x = 3.14; // throws an error because x is not declared
", + "使用 var 关键字来声明变量,会出现重复声明导致变量被覆盖却不会报错的问题:", + "
var camper = 'James';
var camper = 'David';
console.log(camper);
// 打印出 'David'
", + "在上面的代码中, camper 的初始值为 'James',然后又被覆盖成了 'David'。", + "在小型的应用中,你可能不会遇到这样的问题,但是当你的代码规模变得更加庞大的时候,就可能会在不经意间覆盖了之前定义的变量。", + "这样的行为不会报错导致了 debug 非常困难。
", + "在 ES6 中引入了新的关键字 let 来解决 var 关键字带来的潜在问题。", + "如果你在上面的代码中,使用了 let 关键字来代替 var关键字,结果会是一个报错。", + "
let camper = 'James';
let camper = 'David'; // 报错
", + "你可以在浏览器的控制台里看见这个错误。", + "与 var 不同的是, 当使用 let 的时候,同一名字的变量只能被声明一次。", + "请注意 \"use strict\"。这代表着开启了严格模式, 用于检测常见的代码错误以及\"不安全\"的行为,例如:", + "
\"use strict\";
x = 3.14; // x 没有声明导致了报错
", "
", - "Update the code so it only uses the let keyword." + "请更新这段代码,并且在其中只使用 let 关键字" ], "tests": [ { - "text": "var does not exist in code.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'var does not exist in code.');" + "text": "在代码中不应存在 var。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'在代码中不应存在 var。');" }, { - "text": "catName should be Oliver.", - "testString": "assert(catName === \"Oliver\", 'catName should be Oliver.');" + "text": "catName 变量的值应该为 \"Oliver\"。", + "testString": "assert(catName === \"Oliver\", 'catName 变量的值应该为 \"Oliver\"。');" }, { - "text": "quote should be \"Oliver says Meow!\"", - "testString": "assert(quote === \"Oliver says Meow!\", 'quote should be \"Oliver says Meow!\"');" + "text": "quote 变量的值应该为 \"Oliver says Meow!\"", + "testString": "assert(quote === \"Oliver says Meow!\", 'quote 变量的值应该为 \"Oliver says Meow!\"');" } ], "releasedOn": "Feb 17, 2017", @@ -65,33 +65,33 @@ "id": "587d7b87367417b2b2512b40", "title": "Compare Scopes of the var and let Keywords", "description": [ - "When you declare a variable with the var keyword, it is declared globally, or locally if declared inside a function.", - "The let keyword behaves similarly, but with some extra features. When you declare a variable with the let keyword inside a block, statement, or expression, its scope is limited to that block, statement, or expression.", - "For example:", - "
var numArray = [];
for (var i = 0; i < 3; i++) {
  numArray.push(i);
}
console.log(numArray);
// returns [0, 1, 2]
console.log(i);
// returns 3
", - "With the var keyword, i is declared globally. So when i++ is executed, it updates the global variable. This code is similar to the following:", + "当你使用 var 关键字来声明一个变量的时候,这个变量会被声明成全局变量,或是函数内的局部变量。", + "let 关键字的作用类似,但会有一些额外的特性。如果你在代码块、语句或表达式中使用关键字 let 声明变量,这个变量的作用域就被限制在当前的代码块,语句或表达式之中。", + "举个例子:", + "
var numArray = [];
for (var i = 0; i < 3; i++) {
  numArray.push(i);
}
console.log(numArray);
// 返回 [0, 1, 2]
console.log(i);
// 返回 3
", + "当使用 var 关键字的时候, i 会被声明成全局变量。 当 i++ 执行的时候, 它会改变全局变量的值。 这段代码可以看做下面这样:", "
var numArray = [];
var i;
for (i = 0; i < 3; i++) {
  numArray.push(i);
}
console.log(numArray);
// returns [0, 1, 2]
console.log(i);
// returns 3
", - "This behavior will cause problems if you were to create a function and store it for later use inside a for loop that uses the i variable. This is because the stored function will always refer to the value of the updated global i variable.", - "
var printNumTwo;
for (var i = 0; i < 3; i++) {
  if(i === 2){
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// returns 3
", - "As you can see, printNumTwo() prints 3 and not 2. This is because the value assigned to i was updated and the printNumTwo() returns the global i and not the value i had when the function was created in the for loop. The let keyword does not follow this behavior:", - "
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// returns 2
console.log(i);
// returns \"i is not defined\"
", - "i is not defined because it was not declared in the global scope. It is only declared within the for loop statement. printNumTwo() returned the correct value because three different i variables with unique values (0, 1, and 2) were created by the let keyword within the loop statement.", + "如果你在 for 循环中创建了使用 i 变量的函数,那么在后续调用函数的时候,上面提到的这种行为就会导致问题。这是因为函数存储的值会因为全局变量 i的变化而不断的改变。", + "
var printNumTwo;
for (var i = 0; i < 3; i++) {
  if(i === 2){
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// 返回 3
", + "可以看到, printNumTwo() 打印了 3 而不是 2。 这是因为 i 发生了改变,并且函数 printNumTwo() 返回的是全局变量 i的值,而不是 for 循环中创建函数时 i 的值。let 关键字就不会有这种现象:", + "
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// 返回 2
console.log(i);
// 返回 \"没有定义 i 变量\"
", + "i 在全局作用域中没有声明,所以它没有被定义,它的声明只会发生在 for 循环内。在循环执行的时候,let 关键字创建了三个不同的 i 变量,他们的值分别为 0、1 和 2,所以 printNumTwo() 返回了正确的值。", "
", - "Fix the code so that i declared in the if statement is a separate variable than i declared in the first line of the function. Be certain not to use the var keyword anywhere in your code.", - "This exercise is designed to illustrate the difference between how var and let keywords assign scope to the declared variable. When programming a function similar to the one used in this exercise, it is often better to use different variable names to avoid confusion." + "修改这段代码,使得在 if 语句中声明的 i 变量与在函数的第一行声明的 i 变量是彼此独立的。 请注意不要在你的代码的任何地方使用 var 关键字。", + "这个练习说明了使用 varlet关键字声明变量时,作用域之间的不同。当编写类似这个练习中的函数的时候,通常来说最好还是使用不同的变量名来避免误会。" ], "tests": [ { - "text": "var does not exist in code.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'var does not exist in code.');" + "text": "var 不应该在代码中存在。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'var 不应该在代码中存在。');" }, { - "text": "The variable i declared in the if statement should equal \"block scope\".", - "testString": "getUserInput => assert(getUserInput('index').match(/(i\\s*=\\s*).*\\s*.*\\s*.*\\1('|\")block\\s*scope\\2/g), 'The variable i declared in the if statement should equal \"block scope\".');" + "text": "在 if 语句中声明的 i 变量的值是 \"block scope\"。", + "testString": "getUserInput => assert(getUserInput('index').match(/(i\\s*=\\s*).*\\s*.*\\s*.*\\1('|\")block\\s*scope\\2/g), '在 if 语句中声明的 i 变量应该是 \"block scope\"。');" }, { - "text": "checkScope() should return \"function scope\"", - "testString": "assert(checkScope() === \"function scope\", 'checkScope() should return \"function scope\"');" + "text": "checkScope() 应当返回 \"function scope\"", + "testString": "assert(checkScope() === \"function scope\", 'checkScope() 应该返回 \"function scope\"');" } ], "releasedOn": "Feb 17, 2017", @@ -122,29 +122,29 @@ "id": "587d7b87367417b2b2512b41", "title": "Declare a Read-Only Variable with the const Keyword", "description": [ - "let is not the only new way to declare variables. In ES6, you can also declare variables using the const keyword.", - "const has all the awesome features that let has, with the added bonus that variables declared using const are read-only. They are a constant value, which means that once a variable is assigned with const, it cannot be reassigned.", - "
\"use strict\"
const FAV_PET = \"Cats\";
FAV_PET = \"Dogs\"; // returns error
", - "As you can see, trying to reassign a variable declared with const will throw an error. You should always name variables you don't want to reassign using the const keyword. This helps when you accidentally attempt to reassign a variable that is meant to stay constant. A common practice when naming constants is to use all uppercase letters, with words separated by an underscore.", + "let 并不是唯一的新的声明变量的方式。在 ES6里面,你还可以使用 const 关键字来声明变量。", + "const 拥有 let 的所有优点,所不同的是,通过code 声明的变量是只读的。这意味着通过 const 声明的变量只能被赋值一次,而不能被再次赋值。", + "
\"use strict\"
const FAV_PET = \"Cats\";
FAV_PET = \"Dogs\"; // 报错
", + "可以看见,尝试给通过 const 声明的变量再次赋值会报错。你应该使用 const 关键字来对所有不打算再次赋值的变量进行声明。这有助于你避免给一个常量进行额外的再次赋值。一个最佳实践是对所有常量的命名采用全大写字母,并在单词之间使用下划线进行分隔。", "
", - "Change the code so that all variables are declared using let or const. Use let when you want the variable to change, and const when you want the variable to remain constant. Also, rename variables declared with const to conform to common practices, meaning constants should be in all caps." + "改变以下代码,使得所有的变量都使用 letconst 关键词来声明。当变量将会改变的时候使用 let关键字,当变量要保持常量的时候使用 const 关键字。同时,对使用 const 声明的变量进行最佳实践的重命名,变量名中的字母应该都是大写的。" ], "tests": [ { - "text": "var does not exist in your code.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'var does not exist in your code.');" + "text": "var 在代码中不存在。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g),'var 在代码中不存在。');" }, { - "text": "SENTENCE should be a constant variable declared with const.", - "testString": "getUserInput => assert(getUserInput('index').match(/(const SENTENCE)/g), 'SENTENCE should be a constant variable declared with const.');" + "text": "SENTENCE 应该是使用 const 声明的常量。", + "testString": "getUserInput => assert(getUserInput('index').match(/(const SENTENCE)/g), 'SENTENCE 应该是使用 const 声明的常量。');" }, { - "text": "i should be declared with let.", - "testString": "getUserInput => assert(getUserInput('index').match(/(let i)/g), 'i should be declared with let.');" + "text": "i 应该是使用 let 声明的变量。", + "testString": "getUserInput => assert(getUserInput('index').match(/(let i)/g), 'i 应该是使用 let 声明的变量。');" }, { - "text": "console.log should be changed to print the SENTENCE variable.", - "testString": "getUserInput => assert(getUserInput('index').match(/console\\.log\\(\\s*SENTENCE\\s*\\)\\s*;?/g), 'console.log should be adjusted to print the variable SENTENCE.');" + "text": "console.log 应该修改为用于打印 SENTENCE 变量。", + "testString": "getUserInput => assert(getUserInput('index').match(/console\\.log\\(\\s*SENTENCE\\s*\\)\\s*;?/g), 'console.log 应该修改为用于打印 SENTENCE 变量。');" } ], "releasedOn": "Feb 17, 2017", @@ -158,14 +158,14 @@ "function printManyTimes(str) {", " \"use strict\";", "", - " // change code below this line", + " // 在这行以下修改代码", "", " var sentence = str + \" is cool!\";", " for(var i = 0; i < str.length; i+=2) {", " console.log(sentence);", " }", "", - " // change code above this line", + " // 在这行以上修改代码", "", "}", "printManyTimes(\"freeCodeCamp\");" @@ -179,30 +179,30 @@ "id": "587d7b87367417b2b2512b42", "title": "Mutate an Array Declared with const", "description": [ - "The const declaration has many use cases in modern JavaScript.", - "Some developers prefer to assign all their variables using const by default, unless they know they will need to reassign the value. Only in that case, they use let.", - "However, it is important to understand that objects (including arrays and functions) assigned to a variable using const are still mutable. Using the const declaration only prevents reassignment of the variable identifier.", - "
\"use strict\";
const s = [5, 6, 7];
s = [1, 2, 3]; // throws error, trying to assign a const
s[2] = 45; // works just as it would with an array declared with var or let
console.log(s); // returns [5, 6, 45]
", - "As you can see, you can mutate the object [5, 6, 7] itself and the variable s will still point to the altered array [5, 6, 45]. Like all arrays, the array elements in s are mutable, but because const was used, you cannot use the variable identifier s to point to a different array using the assignment operator.", + "在现代的 JavaScript 里,const 声明有很多用法", + "一些开发者倾向默认使用 const 来声明所有变量,除非在他们知道需要更改某个变量的值的时候,才会使用 let", + "然而,重点是要理解对象(包括数组和函数)在使用 const 声明的时候依然是可变的。使用 const来声明只会保证它的标识不会被重新赋值。", + "
\"use strict\";
const s = [5, 6, 7];
s = [1, 2, 3]; // 试图给 const 变量赋值,报错
s[2] = 45; // 与用 var 或 let 声明的数组一样,这个操作也会成功
console.log(s); // 返回 [5, 6, 45]
", + "可以看见,你可以改变 [5, 6, 7] 自身,所以 s 变量指向了改变后的数组 [5, 6, 45]。和所有数组一样,数组 s中的数组元素是可以被改变的,但是因为使用了 const 关键字,你不能使用赋值操作符将变量标识 s 指向另外一个数组", "
", - "An array is declared as const s = [5, 7, 2]. Change the array to [2, 5, 7] using various element assignment." + "这里有一个使用 const s = [5, 7, 2] 声明的数组。使用对各元素赋值的方法将数组改成 [2, 5, 7]。" ], "tests": [ { - "text": "Do not replace const keyword.", - "testString": "getUserInput => assert(getUserInput('index').match(/const/g), 'Do not replace const keyword.');" + "text": "不要替换 const 关键字。", + "testString": "getUserInput => assert(getUserInput('index').match(/const/g), '不要替换 const 关键字。');" }, { - "text": "s should be a constant variable (by using const).", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+s/g), 's should be a constant variable (by using const).');" + "text": "s 应该为常量 (通过使用 const)。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+s/g), 's 应该为常量 (通过使用 const)。');" }, { - "text": "Do not change the original array declaration.", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+s\\s*=\\s*\\[\\s*5\\s*,\\s*7\\s*,\\s*2\\s*\\]\\s*;?/g), 'Do not change the original array declaration.');" + "text": "不要改变原数组的声明。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+s\\s*=\\s*\\[\\s*5\\s*,\\s*7\\s*,\\s*2\\s*\\]\\s*;?/g), '不要改变原数组的声明。');" }, { - "text": "s should be equal to [2, 5, 7].", - "testString": "assert.deepEqual(s, [2, 5, 7], 's should be equal to [2, 5, 7].');" + "text": "s 应该等于 [2, 5, 7]。", + "testString": "assert.deepEqual(s, [2, 5, 7], 's 应该等于 [2, 5, 7]。');" } ], "releasedOn": "Feb 17, 2017", @@ -216,11 +216,11 @@ "const s = [5, 7, 2];", "function editInPlace() {", " \"use strict\";", - " // change code below this line", + " // 在这行以下修改代码", "", " // s = [2, 5, 7]; <- this is invalid", "", - " // change code above this line", + " // 在这行以上修改代码", "}", "editInPlace();" ], @@ -233,28 +233,28 @@ "id": "598f48a36c8c40764b4e52b3", "title": "Prevent Object Mutation", "description": [ - "As seen in the previous challenge, const declaration alone doesn't really protect your data from mutation. To ensure your data doesn't change, JavaScript provides a function Object.freeze to prevent data mutation.", - "Once the object is frozen, you can no longer add, update, or delete properties from it. Any attempt at changing the object will be rejected without an error.", - "
let obj = {
  name:\"FreeCodeCamp\",
  review:\"Awesome\"
};
Object.freeze(obj);
obj.review = \"bad\"; //will be ignored. Mutation not allowed
obj.newProp = \"Test\"; // will be ignored. Mutation not allowed
console.log(obj);
// { name: \"FreeCodeCamp\", review:\"Awesome\"}
", + "通过之前的挑战可以看出, const 声明并不会真的保护你的数据不被改变. 为了确保数据不被改变, Javascript 提供了一个函数 Object.freeze 来防止数据改变。", + "当一个对象被冻结的时候,你不能再对它的属性再进行增、删、改的操作。任何试图改变对象的操作都会被阻止,却不会报错。", + "
let obj = {
  name:\"FreeCodeCamp\",
  review:\"Awesome\"
};
Object.freeze(obj);
obj.review = \"bad\"; //obj 对象被冻结了,这个操作会被忽略
obj.newProp = \"Test\"; // will be ignored. Mutation not allowed
console.log(obj);
// { name: \"FreeCodeCamp\", review:\"Awesome\"}
", "
", - "In this challenge you are going to use Object.freeze to prevent mathematical constants from changing. You need to freeze the MATH_CONSTANTS object so that no one is able alter the value of PI, add, or delete properties ." + "在这个挑战中,你将使用 Object.freeze 来防止数学常量被改变。你需要冻结 MATH_CONSTANTS 对象,使得没有人可以改变 PI 的值,抑或增加或删除属性。" ], "tests": [ { - "text": "Do not replace const keyword.", - "testString": "getUserInput => assert(getUserInput('index').match(/const/g), 'Do not replace const keyword.');" + "text": "不要替换 const 关键字。", + "testString": "getUserInput => assert(getUserInput('index').match(/const/g), '不要替换 const 关键字。');" }, { - "text": "MATH_CONSTANTS should be a constant variable (by using const).", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS/g), 'MATH_CONSTANTS should be a constant variable (by using const).');" + "text": "MATH_CONSTANTS 应该为一个常量 (使用 const)。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS/g), 'MATH_CONSTANTS 应该为一个常量 (使用 const)。');" }, { - "text": "Do not change original MATH_CONSTANTS.", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS\\s+=\\s+{\\s+PI:\\s+3.14\\s+};/g), 'Do not change original MATH_CONSTANTS.');" + "text": "不要改变原始的 MATH_CONSTANTS。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+MATH_CONSTANTS\\s+=\\s+{\\s+PI:\\s+3.14\\s+};/g), '不要改变原始的 MATH_CONSTANTS。');" }, { - "text": "PI equals 3.14.", - "testString": "assert(PI === 3.14, 'PI equals 3.14.');" + "text": "PI 等于 3.14。", + "testString": "assert(PI === 3.14, 'PI 等于 3.14。');" } ], "releasedOn": "Aug 12, 2017", @@ -270,10 +270,10 @@ " const MATH_CONSTANTS = {", " PI: 3.14", " };", - " // change code below this line", + " // 在这行以下修改代码", "", "", - " // change code above this line", + " // 在这行以上修改代码", " try {", " MATH_CONSTANTS.PI = 99;", " } catch( ex ) {", @@ -292,37 +292,37 @@ "id": "587d7b87367417b2b2512b43", "title": "Use Arrow Functions to Write Concise Anonymous Functions", "description": [ - "In JavaScript, we often don't need to name our functions, especially when passing a function as an argument to another function. Instead, we create inline functions. We don't need to name these functions because we do not reuse them anywhere else.", - "To achieve this, we often use the following syntax:", + "在JavaScript里,我们会经常遇到不需要给函数命名的情况,尤其是在需要将以个函数作为参数传给另外一个函数的时候,在这些时候,我们会创建行内函数。因为这些函数不会再其他地方复用,所以我们不要给它们命名。", + "这种情况下,我们通常会使用以下语法:", "
const myFunc = function() {
  const myVar = \"value\";
  return myVar;
}
", - "ES6 provides us with the syntactic sugar to not have to write anonymous functions this way. Instead, you can use arrow function syntax:", + "ES6 提供了其他写匿名函数的方式的语法糖。你可以使用箭头函数:", "
const myFunc = () => {
  const myVar = \"value\";
  return myVar;
}
", - "When there is no function body, and only a return value, arrow function syntax allows you to omit the keyword return as well as the brackets surrounding the code. This helps simplify smaller functions into one-line statements:", + "当不需要函数体,只返回一个值的时候,箭头函数允许你省略 return 关键字和外面的大括号。这样就可以将一个简单的函数简化成一个单行语句。", "
const myFunc= () => \"value\"
", - "This code will still return value by default.", + "这段代码仍然会返回 value", "
", - "Rewrite the function assigned to the variable magic which returns a new Date() to use arrow function syntax. Also make sure nothing is defined using the keyword var." + "使用箭头函数的语法重写 magic 函数,使其返回一个新的 Date()。同时不要用 var 关键字来定义任何变量。" ], "tests": [ { - "text": "User did replace var keyword.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), 'User did replace var keyword.');" + "text": "替换掉 var 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), '替换掉 var 关键字。');" }, { - "text": "magic should be a constant variable (by using const).", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+magic/g), 'magic should be a constant variable (by using const).');" + "text": "magic 应该为一个常量 (使用 const)。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+magic/g), 'magic 应该为一个常量 (使用 const)。');" }, { - "text": "magic is a function.", - "testString": "assert(typeof magic === 'function', 'magic is a function.');" + "text": "magic 是一个 function。", + "testString": "assert(typeof magic === 'function', 'magic 是一个 function。');" }, { - "text": "magic() returns correct date.", - "testString": "assert(magic().getDate() == new Date().getDate(), 'magic() returns correct date.');" + "text": "magic() 返回正确的日期。", + "testString": "assert(magic().getDate() == new Date().getDate(), 'magic() 返回正确的日期。');" }, { - "text": "function keyword was not used.", - "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), 'function keyword was not used.');" + "text": "不要使用 function 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), '不要使用 function 关键字。');" } ], "releasedOn": "Feb 17, 2017", @@ -347,32 +347,32 @@ "id": "587d7b88367417b2b2512b44", "title": "Write Arrow Functions with Parameters", "description": [ - "Just like a normal function, you can pass arguments into arrow functions.", + "和一般的函数一样,你也可以给箭头函数传递参数。", "
// doubles input value and returns it
const doubler = (item) => item * 2;
", - "You can pass more than one argument into arrow functions as well.", + "你可以同样可以给箭头函数传递多个参数。", "
", - "Rewrite the myConcat function which appends contents of arr2 to arr1 so that the function uses arrow function syntax." + "使用箭头函数的语法重写 myConcat 函数,使其可以将 arr2 的内容粘贴在 arr1里。" ], "tests": [ { - "text": "User did replace var keyword.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), 'User did replace var keyword.');" + "text": "替换掉所有的 var 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), '替换掉所有的 var 关键字。');" }, { - "text": "myConcat should be a constant variable (by using const).", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+myConcat/g), 'myConcat should be a constant variable (by using const).');" + "text": "myConcat 应该是一个常量 (使用 const)。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+myConcat/g), 'myConcat 应该是一个常量 (使用 const)。');" }, { - "text": "myConcat should be a function", - "testString": "assert(typeof myConcat === 'function', 'myConcat should be a function');" + "text": "myConcat 应该是一个函数。", + "testString": "assert(typeof myConcat === 'function', 'myConcat 应该是一个函数。');" }, { - "text": "myConcat() returns the correct array", - "testString": "assert(() => { const a = myConcat([1], [2]); return a[0] == 1 && a[1] == 2; }, 'myConcat() returns the correct array');" + "text": "myConcat() 返回正确的 array。", + "testString": "assert(() => { const a = myConcat([1], [2]); return a[0] == 1 && a[1] == 2; }, 'myConcat() 返回正确的 array。');" }, { - "text": "function keyword was not used.", - "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), 'function keyword was not used.');" + "text": "不要使用 function 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), '不要使用 function 关键字。');" } ], "releasedOn": "Feb 17, 2017", @@ -387,7 +387,7 @@ " \"use strict\";", " return arr1.concat(arr2);", "};", - "// test your code", + "// 测试你的代码", "console.log(myConcat([1, 2], [3, 4, 5]));" ], "head": [], @@ -399,44 +399,44 @@ "id": "587d7b88367417b2b2512b45", "title": "Write Higher Order Arrow Functions", "description": [ - "It's time we see how powerful arrow functions are when processing data.", - "Arrow functions work really well with higher order functions, such as map(), filter(), and reduce(), that take other functions as arguments for processing collections of data.", - "Read the following code:", + "我们已经见识到了箭头函数在处理数据时候的强大之处。", + "箭头函数在类似 map, filter, reduce 等需要其他函数作为参数来处理数据的高阶函数里会很好用。" , + "阅读以下代码:", "
FBPosts.filter(function(post) {
  return post.thumbnail !== null && post.shares > 100 && post.likes > 500;
})
", - "We have written this with filter() to at least make it somewhat readable. Now compare it to the following code which uses arrow function syntax instead:", + "我们写下了 filter 函数,并尽量保证可读性。现在让我们用箭头函数来写同样的代码看看:", "
FBPosts.filter((post) => post.thumbnail !== null && post.shares > 100 && post.likes > 500)
", - "This code is more succinct and accomplishes the same task with fewer lines of code.", + "这段代码完成了同样的任务,却变得更加剪短易懂了。", "
", - "Use arrow function syntax to compute the square of only the positive integers (fractions are not integers) in the array realNumberArray and store the new array in the variable squaredIntegers." + "使用箭头函数的语法来计算 squaredIntegers 数组里正整数的平方(分数不是整数)" ], "tests": [ { - "text": "User did replace var keyword.", - "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), 'User did replace var keyword.');" + "text": "替换掉所有的 var 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/var/g), '替换掉所有的 var 关键字。');" }, { - "text": "squaredIntegers should be a constant variable (by using const).", - "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+squaredIntegers/g), 'squaredIntegers should be a constant variable (by using const).');" + "text": "squaredIntegers 应该是一个常量 (使用 const)。", + "testString": "getUserInput => assert(getUserInput('index').match(/const\\s+squaredIntegers/g), 'squaredIntegers 应该是一个常量 (使用 const)。');" }, { - "text": "squaredIntegers should be an array", - "testString": "assert(Array.isArray(squaredIntegers), 'squaredIntegers should be an array');" + "text": "squaredIntegers 应该是一个 array。", + "testString": "assert(Array.isArray(squaredIntegers), 'squaredIntegers 应该是一个 array');" }, { - "text": "squaredIntegers should be [16, 1764, 36]", - "testString": "assert(squaredIntegers[0] === 16 && squaredIntegers[1] === 1764 && squaredIntegers[2] === 36, 'squaredIntegers should be [16, 1764, 36]');" + "text": "squaredIntegers 应该是 [16, 1764, 36]", + "testString": "assert(squaredIntegers[0] === 16 && squaredIntegers[1] === 1764 && squaredIntegers[2] === 36, 'squaredIntegers 应该是 [16, 1764, 36]');" }, { - "text": "function keyword was not used.", - "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), 'function keyword was not used.');" + "text": "不要使用 function 关键字。", + "testString": "getUserInput => assert(!getUserInput('index').match(/function/g), '不要使用 function 关键字。');" }, { - "text": "loop should not be used", - "testString": "getUserInput => assert(!getUserInput('index').match(/(for)|(while)/g), 'loop should not be used');" + "text": "不要使用循环", + "testString": "getUserInput => assert(!getUserInput('index').match(/(for)|(while)/g), '不要使用循环');" }, { - "text": "map, filter, or reduce should be used", - "testString": "getUserInput => assert(getUserInput('index').match(/map|filter|reduce/g), 'map, filter, or reduce should be used');" + "text": "请使用 map, filter, 或者 reduce。", + "testString": "getUserInput => assert(getUserInput('index').match(/map|filter|reduce/g), '请使用 map, filter, 或者 reduce。');" } ], "releasedOn": "Feb 17, 2017", @@ -450,12 +450,12 @@ "const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34];", "const squareList = (arr) => {", " \"use strict\";", - " // change code below this line", + " // 在这行以下修改代码", " const squaredIntegers = arr;", - " // change code above this line", + " // 在这行以上修改代码", " return squaredIntegers;", "};", - "// test your code", + "// 测试你的代码", "const squaredIntegers = squareList(realNumberArray);", "console.log(squaredIntegers);" ], @@ -468,24 +468,24 @@ "id": "587d7b88367417b2b2512b46", "title": "Set Default Parameters for Your Functions", "description": [ - "In order to help us create more flexible functions, ES6 introduces default parameters for functions.", - "Check out this code:", + "ES6 里允许给函数传入默认参数,来构建更加灵活的函数。", + "查看以下代码:", "
function greeting(name = \"Anonymous\") {
  return \"Hello \" + name;
}
console.log(greeting(\"John\")); // Hello John
console.log(greeting()); // Hello Anonymous
", - "The default parameter kicks in when the argument is not specified (it is undefined). As you can see in the example above, the parameter name will receive its default value \"Anonymous\" when you do not provide a value for the parameter. You can add default values for as many parameters as you want.", + "默认参数会在参数没有被指定(值为 undefined )的时候起作用。在上面的例子中,参数 name 会在没有得到新的值的时候,默认使用值 \"Anonymous\"。你还可以给多个参数赋予默认值。", "
", - "Modify the function increment by adding default parameters so that it will add 1 to number if value is not specified." + "给函数 increment 加上默认参数,使得在 value 没有被赋值的时候,默认给 number 加1。" ], "tests": [ { - "text": "The result of increment(5, 2) should be 7.", - "testString": "assert(increment(5, 2) === 7, 'The result of increment(5, 2) should be 7.');" + "text": "increment(5, 2) 的结果应该为 7。", + "testString": "assert(increment(5, 2) === 7, 'increment(5, 2) 的结果应该为 7。');" }, { - "text": "The result of increment(5) should be 6.", - "testString": "assert(increment(5) === 6, 'The result of increment(5) should be 6.');" + "text": "increment(5) 的结果应该为 6。", + "testString": "assert(increment(5) === 6, 'increment(5) 的结果应该为 6。');" }, { - "text": "default parameter 1 was used for value.", + "text": "参数 value 的默认值应该为 1。", "testString": "getUserInput => assert(getUserInput('index').match(/value\\s*=\\s*1/g), 'default parameter 1 was used for value.');" } ], @@ -503,8 +503,8 @@ " return number + value;", " };", "})();", - "console.log(increment(5, 2)); // returns 7", - "console.log(increment(5)); // returns NaN" + "console.log(increment(5, 2)); // 返回 7", + "console.log(increment(5)); // 返回 NaN" ], "head": [], "tail": [] @@ -515,33 +515,33 @@ "id": "587d7b88367417b2b2512b47", "title": "Use the Rest Operator with Function Parameters", "description": [ - "In order to help us create more flexible functions, ES6 introduces the rest operator for function parameters. With the rest operator, you can create functions that take a variable number of arguments. These arguments are stored in an array that can be accessed later from inside the function.", - "Check out this code:", - "
function howMany(...args) {
  return \"You have passed \" + args.length + \" arguments.\";
}
console.log(howMany(0, 1, 2)); // You have passed 3 arguments
console.log(howMany(\"string\", null, [1, 2, 3], { })); // You have passed 4 arguments.
", - "The rest operator eliminates the need to check the args array and allows us to apply map(), filter() and reduce() on the parameters array.", + "ES6 推出了用于函数参数的rest 操作符 帮助我们创建更加灵活的函数。 在 rest 操作符的帮助下,你可以创建有一个变量来接受多个参数的函数。 这些参数被储存在一个可以在函数内部读取的数组中。", + "请看以下代码:", + "
function howMany(...args) {
  return \"You have passed \" + args.length + \" arguments.\";
}
console.log(howMany(0, 1, 2)); // 你需要输入3个参数。
console.log(howMany(\"string\", null, [1, 2, 3], { })); //你需要输入4个参数。
", + "rest 操作符可以避免查看 args 数组的需求,并且允许我们在参数数组上使用 map(), fiter(),和 reduce()", "
", - "Modify the function sum so that it uses the rest operator and it works in the same way with any number of parameters." + "修改 sum 函数,来让它使用 rest操作符,并且它可以在有任何数量的参数时以相同的形式工作" ], "tests": [ { - "text": "The result of sum(0,1,2) should be 3", - "testString": "assert(sum(0,1,2) === 3, 'The result of sum(0,1,2) should be 3');" + "text": "sum(0,1,2) 的返回结果应该为3。", + "testString": "assert(sum(0,1,2) === 3, 'sum(0,1,2) 的返回结果应该为3。');" }, { - "text": "The result of sum(1,2,3,4) should be 10", - "testString": "assert(sum(1,2,3,4) === 10, 'The result of sum(1,2,3,4) should be 10');" + "text": "sum(1,2,3,4) 的返回结果应该为10。", + "testString": "assert(sum(1,2,3,4) === 10, 'sum(1,2,3,4) 的返回结果应该为10。');" }, { - "text": "The result of sum(5) should be 5", - "testString": "assert(sum(5) === 5, 'The result of sum(5) should be 5');" + "text": "sum(5) 的返回结果应该为5。", + "testString": "assert(sum(5) === 5, 'sum(5) 的返回结果应该为5。');" }, { - "text": "The result of sum() should be 0", - "testString": "assert(sum() === 0, 'The result of sum() should be 0');" + "text": "sum()的返回结果应该为 0。", + "testString": "assert(sum() === 0, 'sum()的返回结果应该为 0。');" }, { - "text": "The sum function uses the ... spread operator on the args parameter.", - "testString": "getUserInput => assert(getUserInput('index').match(/function\\s+sum\\s*\\(\\s*...args\\s*\\)\\s*{/g), 'The sum function uses the ... spread operator on the args parameter.');" + "text": "对 sum 函数的 args 参数使用了 ... 展开操作符。", + "testString": "getUserInput => assert(getUserInput('index').match(/function\\s+sum\\s*\\(\\s*...args\\s*\\)\\s*{/g), '对 sum 函数的 args 参数使用了 ... 展开操作符。');" } ], "releasedOn": "Feb 17, 2017", @@ -570,30 +570,30 @@ "id": "587d7b89367417b2b2512b48", "title": "Use the Spread Operator to Evaluate Arrays In-Place", "description": [ - "ES6 introduces the spread operator, which allows us to expand arrays and other expressions in places where multiple parameters or elements are expected.", - "The ES5 code below uses apply() to compute the maximum value in an array:", - "
var arr = [6, 89, 3, 45];
var maximus = Math.max.apply(null, arr); // returns 89
", - "We had to use Math.max.apply(null, arr) because Math.max(arr) returns NaN. Math.max() expects comma-separated arguments, but not an array.", + "ES6 允许我们使用 展开操作符 来展开数组,以及需要多个参数或元素的表达式。", + "下面的 ES5 代码使用了 apply() 来计算数组的最大值:", + "
var arr = [6, 89, 3, 45];
var maximus = Math.max.apply(null, arr); // 返回 89
", + "我们必须使用 Math.max.apply(null,arr),是因为直接调用 Math.max(arr) 会返回 NaNMath.max() 函数需要传入的是一系列由逗号分隔的参数,而不是一个数组。", "The spread operator makes this syntax much better to read and maintain.", - "
const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr); // returns 89
", - "...arr returns an unpacked array. In other words, it spreads the array.", - "However, the spread operator only works in-place, like in an argument to a function or in an array literal. The following code will not work:", - "
const spreaded = ...arr; // will throw a syntax error
", + "
const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr); // 返回 89
", + "...arr 返回了一个“打开”的数组。 或者说它 展开 了数组。", + "然而,展开操作符只能够在函数的参数中,或者数组之中使用。下面的代码将会报错:", + "
const spreaded = ...arr; // 将会发生语法错误
", "
", - "Copy all contents of arr1 into another array arr2 using the spread operator." + "使用展开操作符将 arr1 中的内容都赋值到 arr2 中去。" ], "tests": [ { - "text": "arr2 is correct copy of arr1.", - "testString": "assert(arr2.every((v, i) => v === arr1[i]), 'arr2 is correct copy of arr1.');" + "text": "arr2 的值是由 arr1 拷贝而来的。", + "testString": "assert(arr2.every((v, i) => v === arr1[i]), 'arr2 的值是由 arr1 拷贝而来的。');" }, { - "text": "... spread operator was used to duplicate arr1.", - "testString": "getUserInput => assert(getUserInput('index').match(/\\[\\s*...arr1\\s*\\]/g),'... spread operator was used to duplicate arr1.');" + "text": "用... 展开操作符来赋值 arr1。", + "testString": "getUserInput => assert(getUserInput('index').match(/\\[\\s*...arr1\\s*\\]/g),'用... 展开操作符来赋值 arr1。');" }, { - "text": "arr2 remains unchanged when arr1 is changed.", - "testString": "assert((arr1, arr2) => {arr1.push('JUN'); return arr2.length < arr1.length},'arr2 remains unchanged when arr1 is changed.');" + "text": "当 arr1 改变的时候,arr2 不会改变。", + "testString": "assert((arr1, arr2) => {arr1.push('JUN'); return arr2.length < arr1.length},'当 arr1 改变的时候,arr2 不会改变。');" } ], "releasedOn": "Feb 17, 2017", @@ -608,7 +608,7 @@ "let arr2;", "(function() {", " \"use strict\";", - " arr2 = []; // change this line", + " arr2 = []; // 改变这一行", "})();", "console.log(arr2);" ], @@ -621,30 +621,30 @@ "id": "587d7b89367417b2b2512b49", "title": "Use Destructuring Assignment to Assign Variables from Objects", "description": [ - "We saw earlier how spread operator can effectively spread, or unpack, the contents of the array.", - "We can do something similar with objects as well. Destructuring assignment is special syntax for neatly assigning values taken directly from an object to variables.", - "Consider the following ES5 code:", + "我们之前看到了展开操作符是如何詹卡数组的内容的。", + "我们队对象也可以做同样的操作。 解构赋值 就是可以从对象中直接获取对应值的语法。", + "看看以下 ES5 的代码:", "
var voxel = {x: 3.6, y: 7.4, z: 6.54 };
var x = voxel.x; // x = 3.6
var y = voxel.y; // y = 7.4
var z = voxel.z; // z = 6.54
", - "Here's the same assignment statement with ES6 destructuring syntax:", + "使用 ES6 的解构语法可以完成同样的赋值语句:", "
const { x, y, z } = voxel; // x = 3.6, y = 7.4, z = 6.54
", - "If instead you want to store the values of voxel.x into a, voxel.y into b, and voxel.z into c, you have that freedom as well.", + "如果你想将 voxel.x, voxel.y, voxel.z 的值分别赋给 a, b, c,可以用以下这种很棒的方式:", "
const { x : a, y : b, z : c } = voxel // a = 3.6, b = 7.4, c = 6.54
", - "You may read it as \"get the field x and copy the value into a,\" and so on.", + "你可以这样理解:“将 x 地址中的值拷贝到 a 当中去。”,等等。", "
", - "Use destructuring to obtain the length of the input string str, and assign the length to len in line." + "使用解构语法去得到输入的 str 字符串的长度,并将长度赋值给 len。" ], "tests": [ { - "text": "the function getLength() returns a number.", - "testString": "assert(typeof getLength('') === 'number', 'the function getLength() returns a number.');" + "text": "函数 getLength() 返回一个数字。", + "testString": "assert(typeof getLength('') === 'number', '函数 getLength() 返回一个数字。');" }, { - "text": "getLength(\"FreeCodeCamp\") should be 12", - "testString": "assert(getLength(\"FreeCodeCamp\") === 12, 'getLength(\"FreeCodeCamp\") should be 12');" + "text": "getLength(\"FreeCodeCamp\") 应该返回 12。", + "testString": "assert(getLength(\"FreeCodeCamp\") === 12, 'getLength(\"FreeCodeCamp\") 应该返回 12。');" }, { - "text": "destructuring with reassignment was used", - "testString": "getUserInput => assert(getUserInput('index').match(/\\{\\s*length\\s*:\\s*len\\s*}\\s*=\\s*str/g),'destructuring with reassignment was used');" + "text": "使用解构语法来重新赋值。", + "testString": "getUserInput => assert(getUserInput('index').match(/\\{\\s*length\\s*:\\s*len\\s*}\\s*=\\s*str/g),'使用解构语法来重新赋值。');" } ], "releasedOn": "Feb 17, 2017", @@ -658,11 +658,11 @@ "function getLength(str) {", " \"use strict\";", "", - " // change code below this line", + " // 在这行以下修改代码", " const length = 0; // change this", - " // change code above this line", + " // 在这行以上修改代码", "", - " return len; // you must assign length to len in line", + " return len; // 你必须在这行将 length 赋值给 len", "", "}", "", @@ -677,21 +677,21 @@ "id": "587d7b89367417b2b2512b4a", "title": "Use Destructuring Assignment to Assign Variables from Nested Objects", "description": [ - "We can similarly destructure nested objects into variables.", - "Consider the following code:", + "同样,我们可以将 嵌套的对象解构到变量中。", + "请看以下代码:", "
const a = {
  start: { x: 5, y: 6},
  end: { x: 6, y: -9 }
};
const { start : { x: startX, y: startY }} = a;
console.log(startX, startY); // 5, 6
", - "In the example above, the variable start is assigned the value of a.start, which is also an object.", + "在上面的例子里,a.start 将值赋给了变量 startstart 同样也是个对象。", "
", - "Use destructuring assignment to obtain max of forecast.tomorrow and assign it to maxOfTomorrow." + "使用解构赋值来得到 forecast.tomorrowmax,并将其赋值给 maxOfTomorrow。" ], "tests": [ { - "text": "maxOfTomorrow equals 84.6", - "testString": "assert(getMaxOfTmrw(LOCAL_FORECAST) === 84.6, 'maxOfTomorrow equals 84.6');" + "text": "maxOfTomorrow 等于 84.6", + "testString": "assert(getMaxOfTmrw(LOCAL_FORECAST) === 84.6, 'maxOfTomorrow 等于 84.6');" }, { - "text": "nested destructuring was used", - "testString": "getUserInput => assert(getUserInput('index').match(/\\{\\s*tomorrow\\s*:\\s*\\{\\s*max\\s*:\\s*maxOfTomorrow\\s*\\}\\s*\\}\\s*=\\s*forecast/g),'nested destructuring was used');" + "text": "使用嵌套解构", + "testString": "getUserInput => assert(getUserInput('index').match(/\\{\\s*tomorrow\\s*:\\s*\\{\\s*max\\s*:\\s*maxOfTomorrow\\s*\\}\\s*\\}\\s*=\\s*forecast/g),'使用嵌套解构');" } ], "releasedOn": "Feb 17, 2017", @@ -709,13 +709,13 @@ "", "function getMaxOfTmrw(forecast) {", " \"use strict\";", - " // change code below this line", - " const maxOfTomorrow = undefined; // change this line", - " // change code above this line", + " // 在这行以下修改代码", + " const maxOfTomorrow = undefined; // 改变这一行", + " // 在这行以上修改代码", " return maxOfTomorrow;", "}", "", - "console.log(getMaxOfTmrw(LOCAL_FORECAST)); // should be 84.6" + "console.log(getMaxOfTmrw(LOCAL_FORECAST)); // 应该为 84.6" ], "head": [], "tail": [] @@ -761,9 +761,9 @@ "let a = 8, b = 6;", "(() => {", " \"use strict\";", - " // change code below this line", + " // 在这行以下修改代码", " ", - " // change code above this line", + " // 在这行以上修改代码", "})();", "console.log(a); // should be 6", "console.log(b); // should be 8" @@ -810,9 +810,9 @@ "const source = [1,2,3,4,5,6,7,8,9,10];", "function removeFirstTwo(list) {", " \"use strict\";", - " // change code below this line", + " // 在这行以下修改代码", " arr = list; // change this", - " // change code above this line", + " // 在这行以上修改代码", " return arr;", "}", "const arr = removeFirstTwo(source);", @@ -871,12 +871,12 @@ "const half = (function() {", " \"use strict\"; // do not change this line", "", - " // change code below this line", + " // 在这行以下修改代码", " return function half(stats) {", " // use function argument destructuring", " return (stats.max + stats.min) / 2.0;", " };", - " // change code above this line", + " // 在这行以上修改代码", "", "})();", "console.log(stats); // should be object", @@ -931,9 +931,9 @@ "function makeList(arr) {", " \"use strict\";", "", - " // change code below this line", + " // 在这行以下修改代码", " const resultDisplayArray = null;", - " // change code above this line", + " // 在这行以上修改代码", "", " return resultDisplayArray;", "}", @@ -984,13 +984,13 @@ "contents": [ "const createPerson = (name, age, gender) => {", " \"use strict\";", - " // change code below this line", + " // 在这行以下修改代码", " return {", " name: name,", " age: age,", " gender: gender", " };", - " // change code above this line", + " // 在这行以上修改代码", "};", "console.log(createPerson(\"Zodiac Hasbro\", 56, \"male\")); // returns a proper object" ], @@ -1028,7 +1028,7 @@ "ext": "js", "name": "index", "contents": [ - "// change code below this line", + "// 在这行以下修改代码", "const bicycle = {", " gear: 2,", " setGear: function(newGear) {", @@ -1036,7 +1036,7 @@ " this.gear = newGear;", " }", "};", - "// change code above this line", + "// 在这行以上修改代码", "bicycle.setGear(3);", "console.log(bicycle.gear);" ], @@ -1362,4 +1362,4 @@ } } ] -} \ No newline at end of file +} diff --git a/02-javascript-algorithms-and-data-structures/es6.md b/02-javascript-algorithms-and-data-structures/es6.md new file mode 100644 index 0000000..0d4b7df --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/es6.md @@ -0,0 +1,25 @@ +# Introduction to the ES6 Challenges # + +ECMAScript is a standardized version of JavaScript with the goal of unifying the language's specifications and features. As all major browsers and JavaScript-runtimes follow this specification, the term ECMAScript is interchangeable with the term JavaScript. + +Most of the challenges on freeCodeCamp use the ECMAScript 5 (ES5) specification of the language, finalized in 2009. But JavaScript is an evolving programming language. As features are added and revisions are made, new versions of the language are released for use by developers. + +The most recent standardized version is called ECMAScript 6 (ES6), released in 2015. This new version of the language adds some powerful features that will be covered in this section of challenges, including: + + +* Arrow functions + +* Classes + +* Modules + +* Promises + +* Generators + +* let and const + + +## Note ## + +Not all browsers support ES6 features. If you use ES6 in your own projects, you may need to use a program (transpiler) to convert your ES6 code into ES5 until browsers support ES6. diff --git a/02-javascript-algorithms-and-data-structures/functional-programming.md b/02-javascript-algorithms-and-data-structures/functional-programming.md new file mode 100644 index 0000000..c731e82 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/functional-programming.md @@ -0,0 +1,15 @@ +# Introduction to the Functional Programming Challenges # + +Functional programming is an approach to software development based around the evaluation of functions. Like mathematics, functions in programming map input to output to produce a result. You can combine basic functions in many ways to build more and more complex programs. + +Functional programming follows a few core principles: + + +* Functions are independent from the state of the program or global variables. They only depend on the arguments passed into them to make a calculation + +* Functions try to limit any changes to the state of the program and avoid changes to the global objects holding data + +* Functions have minimal side effects in the program + + +The functional programming software development approach breaks a program into small, testable parts. This section covers basic functional programming principles in JavaScript. \ No newline at end of file diff --git a/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json b/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json index a4a3929..53827f4 100644 --- a/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json +++ b/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.json @@ -8,38 +8,38 @@ "id": "a3566b1109230028080c9345", "title": "Sum All Numbers in a Range", "description": [ - "We'll pass you an array of two numbers. Return the sum of those two numbers plus the sum of all the numbers between them.", - "The lowest number will not always come first.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "给出一个含有两个数字的数组,我们需要写一个函数,让它返回这两个数字间所有数字(包含这两个数字)的总和。", + "注意,较小数不一定总是出现在数组的第一个元素。", + "如果你遇到了问题,请点击 帮助。" ], "hints": [ - "Use Math.max() to find the maximum value of two numbers.", - "Use Math.min() to find the minimum value of two numbers.", - "Remember to that you must add all the numbers in between so this would require a way to get those numbers." + "使用 Math.max() 来获取两数中较大的数。", + "使用 Math.min() 来获取两数中较小的数。", + "注意,既然需要对两数之间的所有数求和,那就先要考虑好如何获取这些数。" ], "solutions": [ "function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}" ], "tests": [ { - "text": "sumAll([1, 4]) should return a number.", - "testString": "assert(typeof sumAll([1, 4]) === 'number', 'sumAll([1, 4]) should return a number.');" + "text": "sumAll([1, 4]) 应该返回一个数字。", + "testString": "assert(typeof sumAll([1, 4]) === 'number', 'sumAll([1, 4]) 应该返回一个数字。');" }, { - "text": "sumAll([1, 4]) should return 10.", - "testString": "assert.deepEqual(sumAll([1, 4]), 10, 'sumAll([1, 4]) should return 10.');" + "text": "sumAll([1, 4]) 应该返回 10。", + "testString": "assert.deepEqual(sumAll([1, 4]), 10, 'sumAll([1, 4]) 应该返回 10。');" }, { - "text": "sumAll([4, 1]) should return 10.", - "testString": "assert.deepEqual(sumAll([4, 1]), 10, 'sumAll([4, 1]) should return 10.');" + "text": "sumAll([4, 1]) 应该返回 10。", + "testString": "assert.deepEqual(sumAll([4, 1]), 10, 'sumAll([4, 1]) 应该返回 10。');" }, { - "text": "sumAll([5, 10]) should return 45.", - "testString": "assert.deepEqual(sumAll([5, 10]), 45, 'sumAll([5, 10]) should return 45.');" + "text": "sumAll([5, 10]) 应该返回 45。", + "testString": "assert.deepEqual(sumAll([5, 10]), 45, 'sumAll([5, 10]) 应该返回 45。');" }, { - "text": "sumAll([10, 5]) should return 45.", - "testString": "assert.deepEqual(sumAll([10, 5]), 45, 'sumAll([10, 5]) should return 45.');" + "text": "sumAll([10, 5]) 应该返回 45。", + "testString": "assert.deepEqual(sumAll([10, 5]), 45, 'sumAll([10, 5]) 应该返回 45。');" } ], "MDNlinks": [ @@ -70,73 +70,73 @@ "id": "a5de63ebea8dbee56860f4f2", "title": "Diff Two Arrays", "description": [ - "Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code.", - "Note
You can return the array with its elements in any order." + "在这道题目中,我们需要写一个函数,比较两个数组,返回一个新的数组。这个新数组需要包含传入的两个数组所有元素中,仅在其中一个数组里出现的元素。如果某个元素同时出现在两个数组中,则不应包含在返回的数组里。换言之,我们需要返回这两个数组的对称差。", + "如果你遇到了问题,请点击 帮助。", + "注意:
返回数组中的元素顺序不会影响测试结果。" ], "solutions": [ "function diffArray(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}" ], "tests": [ { - "text": "diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) should return an array.", - "testString": "assert(typeof diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) === \"object\", 'diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) should return an array.');" + "text": "diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) 应该返回一个数组。", + "testString": "assert(typeof diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) === \"object\", 'diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) 应该返回一个数组。');" }, { - "text": "[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [\"pink wool\"].", - "testString": "assert.sameMembers(diffArray([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"pink wool\"], '[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [\"pink wool\"].');" + "text": "[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 [\"pink wool\"]。", + "testString": "assert.sameMembers(diffArray([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"pink wool\"], '[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 [\"pink wool\"]。');" }, { - "text": "[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an array with one item.", - "testString": "assert(diffArray([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 1, '[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an array with one item.');" + "text": "[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个长度为 1 的数组。", + "testString": "assert(diffArray([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 1, '[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个长度为 1 的数组。');" }, { - "text": "[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [\"diorite\", \"pink wool\"].", - "testString": "assert.sameMembers(diffArray([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"diorite\", \"pink wool\"], '[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [\"diorite\", \"pink wool\"].');" + "text": "[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 [\"diorite\", \"pink wool\"]。", + "testString": "assert.sameMembers(diffArray([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"diorite\", \"pink wool\"], '[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 [\"diorite\", \"pink wool\"]。');" }, { - "text": "[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an array with two items.", - "testString": "assert(diffArray([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 2, '[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an array with two items.');" + "text": "[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个长度为 2 的数组。", + "testString": "assert(diffArray([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 2, '[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个长度为 2 的数组。');" }, { - "text": "[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [].", - "testString": "assert.sameMembers(diffArray([\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [], '[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return [].');" + "text": "[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 []。", + "testString": "assert.sameMembers(diffArray([\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [], '[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回 []。');" }, { - "text": "[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an empty array.", - "testString": "assert(diffArray([\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 0, '[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] should return an empty array.');" + "text": "[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个空数组。", + "testString": "assert(diffArray([\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]).length === 0, '[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"] 应该返回一个空数组。');" }, { - "text": "[1, 2, 3, 5], [1, 2, 3, 4, 5] should return [4].", - "testString": "assert.sameMembers(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], '[1, 2, 3, 5], [1, 2, 3, 4, 5] should return [4].');" + "text": "[1, 2, 3, 5], [1, 2, 3, 4, 5] 应该返回 [4]。", + "testString": "assert.sameMembers(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], '[1, 2, 3, 5], [1, 2, 3, 4, 5] 应该返回 [4]。');" }, { - "text": "[1, 2, 3, 5], [1, 2, 3, 4, 5] should return an array with one item.", - "testString": "assert(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]).length === 1, '[1, 2, 3, 5], [1, 2, 3, 4, 5] should return an array with one item.');" + "text": "[1, 2, 3, 5], [1, 2, 3, 4, 5] 应该返回一个长度为 1 的数组。", + "testString": "assert(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]).length === 1, '[1, 2, 3, 5], [1, 2, 3, 4, 5] 应该返回一个长度为 1 的数组。');" }, { - "text": "[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] should return [\"piglet\", 4].", - "testString": "assert.sameMembers(diffArray([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]), [\"piglet\", 4], '[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] should return [\"piglet\", 4].');" + "text": "[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] 应该返回 [\"piglet\", 4]。", + "testString": "assert.sameMembers(diffArray([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]), [\"piglet\", 4], '[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] 应该返回 [\"piglet\", 4]。');" }, { - "text": "[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] should return an array with two items.", - "testString": "assert(diffArray([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]).length === 2, '[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] should return an array with two items.');" + "text": "[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] 应该返回一个长度为 2 的数组。", + "testString": "assert(diffArray([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]).length === 2, '[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4] 应该返回一个长度为 2 的数组。');" }, { - "text": "[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] should return [\"snuffleupagus\", \"cookie monster\", \"elmo\"].", - "testString": "assert.sameMembers(diffArray([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]), [\"snuffleupagus\", \"cookie monster\", \"elmo\"], '[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] should return [\"snuffleupagus\", \"cookie monster\", \"elmo\"].');" + "text": "[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] 应该返回 [\"snuffleupagus\", \"cookie monster\", \"elmo\"]。", + "testString": "assert.sameMembers(diffArray([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]), [\"snuffleupagus\", \"cookie monster\", \"elmo\"], '[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] 应该返回 [\"snuffleupagus\", \"cookie monster\", \"elmo\"]。');" }, { - "text": "[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] should return an array with three items.", - "testString": "assert(diffArray([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]).length === 3, '[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] should return an array with three items.');" + "text": "[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] 应该返回一个长度为 3 的数组。", + "testString": "assert(diffArray([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]).length === 3, '[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"] 应该返回一个长度为 3 的数组。');" }, { - "text": "[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] should return [1, \"calf\", 3, \"piglet\", 7, \"filly\"].", - "testString": "assert.sameMembers(diffArray([1, \"calf\", 3, \"piglet\"], [7, \"filly\"]), [1, \"calf\", 3, \"piglet\", 7, \"filly\"], '[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] should return [1, \"calf\", 3, \"piglet\", 7, \"filly\"].');" + "text": "[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] 应该返回 [1, \"calf\", 3, \"piglet\", 7, \"filly\"]。", + "testString": "assert.sameMembers(diffArray([1, \"calf\", 3, \"piglet\"], [7, \"filly\"]), [1, \"calf\", 3, \"piglet\", 7, \"filly\"], '[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] 应该返回 [1, \"calf\", 3, \"piglet\", 7, \"filly\"]。');" }, { - "text": "[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] should return an array with six items.", - "testString": "assert(diffArray([1, \"calf\", 3, \"piglet\"], [7, \"filly\"]).length === 6, '[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] should return an array with six items.');" + "text": "[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] 应该返回一个长度为 6 的数组。", + "testString": "assert(diffArray([1, \"calf\", 3, \"piglet\"], [7, \"filly\"]).length === 6, '[1, \"calf\", 3, \"piglet\"], [7, \"filly\"] 应该返回一个长度为 6 的数组。');" } ], "MDNlinks": [ @@ -156,7 +156,7 @@ "contents": [ "function diffArray(arr1, arr2) {", " var newArr = [];", - " // Same, same; but different.", + " // 这是一个党异伐同的过程", " return newArr;", "}", "", @@ -171,34 +171,34 @@ "id": "a39963a4c10bc8b4d4f06d7e", "title": "Seek and Destroy", "description": [ - "You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.", - "Note
You have to use the arguments object.", - "Remember to use Read-Search-Ask if you get stuck. Write your own code." + "在这道题目中,我们要写一个叫 destroyer 的函数。传给它的第一个参数是数组,我们称他为初始数组。后续的参数数量是不确定的,可能有一个或多个。你需要做的是,从初始数组中移除所有与后续参数相等的元素,并返回移除元素后的数组。", + "注意:
你可以使用 arguments 对象,也可以使用 ...,即“剩余参数”(Rest Parameters)语法。", + "如果你遇到了问题,请点击 帮助。" ], "tests": [ { - "text": "destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1].", - "testString": "assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1].');" + "text": "destroyer([1, 2, 3, 1, 2, 3], 2, 3) 应该返回 [1, 1]。", + "testString": "assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'destroyer([1, 2, 3, 1, 2, 3], 2, 3) 应该返回 [1, 1]。');" }, { - "text": "destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) should return [1, 5, 1].", - "testString": "assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) should return [1, 5, 1].');" + "text": "destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) 应该返回 [1, 5, 1]。", + "testString": "assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) 应该返回 [1, 5, 1]。');" }, { - "text": "destroyer([3, 5, 1, 2, 2], 2, 3, 5) should return [1].", - "testString": "assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], 'destroyer([3, 5, 1, 2, 2], 2, 3, 5) should return [1].');" + "text": "destroyer([3, 5, 1, 2, 2], 2, 3, 5) 应该返回 [1]。", + "testString": "assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], 'destroyer([3, 5, 1, 2, 2], 2, 3, 5) 应该返回 [1]。');" }, { - "text": "destroyer([2, 3, 2, 3], 2, 3) should return [].", - "testString": "assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], 'destroyer([2, 3, 2, 3], 2, 3) should return [].');" + "text": "destroyer([2, 3, 2, 3], 2, 3) 应该返回 []。", + "testString": "assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], 'destroyer([2, 3, 2, 3], 2, 3) 应该返回 []。');" }, { - "text": "destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53) should return [\"hamburger\"].", - "testString": "assert.deepEqual(destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53), [\"hamburger\"], 'destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53) should return [\"hamburger\"].');" + "text": "destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53) 应该返回 [\"hamburger\"]。", + "testString": "assert.deepEqual(destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53), [\"hamburger\"], 'destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53) 应该返回 [\"hamburger\"]。');" }, { - "text": "destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\") should return [12,92,65].", - "testString": "assert.deepEqual(destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\"), [12,92,65], 'destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\") should return [12,92,65].');" + "text": "destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\") 应该返回 [12,92,65]。", + "testString": "assert.deepEqual(destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\"), [12,92,65], 'destroyer([\"possum\", \"trollo\", 12, \"safari\", \"hotdog\", 92, 65, \"grandma\", \"bugati\", \"trojan\", \"yacht\"], \"yacht\", \"possum\", \"trollo\", \"safari\", \"hotdog\", \"grandma\", \"bugati\", \"trojan\") 应该返回 [12,92,65]。');" } ], "isRequired": true, @@ -217,7 +217,7 @@ "name": "index", "contents": [ "function destroyer(arr) {", - " // Remove all the values", + " // 删掉那些值", " return arr;", "}", "", @@ -232,37 +232,37 @@ "id": "a8e512fbe388ac2f9198f0fa", "title": "Wherefore art thou", "description": [ - "Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.", - "For example, if the first argument is [{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], and the second argument is { last: \"Capulet\" }, then you must return the third object from the array (the first argument), because it contains the name and its value, that was passed on as the second argument.", - "Remember to use Read-Search-Ask if you get stuck. Write your own code." + "在这道题目中,我们要写一个函数,它接收两个参数:第一个参数是对象数组,第二个参数是一个对象。我们需要从对象数组中找出与第二个参数相等或包含第二个参数的所有对象,并以对象数组的形式返回。其中,相等的意思是原数组中的对象与第二个参数中对象的所有键值对完全相等;包含的意思是只要第二个参数中对象的所有键存在于原数组对象中,且它们对应的值相同即可。", + "比如,如果第一个参数是 [{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }],第二个参数是 { last: \"Capulet\" }。那么你需要以对象数组的形式返回第一个参数中的第三个元素,因为它包含第二个参数中定义的键 last,且对应的值 \"Capulet\" 相同", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function whatIsInAName(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}" ], "tests": [ { - "text": "whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }) should return [{ first: \"Tybalt\", last: \"Capulet\" }].", - "testString": "assert.deepEqual(whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }), [{ first: \"Tybalt\", last: \"Capulet\" }], 'whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }) should return [{ first: \"Tybalt\", last: \"Capulet\" }].');" + "text": "whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }) 应该返回 [{ first: \"Tybalt\", last: \"Capulet\" }]。", + "testString": "assert.deepEqual(whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }), [{ first: \"Tybalt\", last: \"Capulet\" }], 'whatIsInAName([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }) 应该返回 [{ first: \"Tybalt\", last: \"Capulet\" }]。');" }, { - "text": "whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }) should return [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }].", - "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }), [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], 'whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }) should return [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }].');" + "text": "whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }) 应该返回 [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }]。", + "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }), [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], 'whatIsInAName([{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }], { \"apple\": 1 }) 应该返回 [{ \"apple\": 1 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2 }]。');" }, { - "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }) should return [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }].", - "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }), [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }) should return [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }].');" + "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }]。", + "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }), [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"bat\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }]。');" }, { - "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }) should return [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }].", - "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }), [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }) should return [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }].');" + "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }]。", + "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }), [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }], { \"apple\": 1, \"cookie\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2, \"cookie\": 2 }]。');" }, { - "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, { \"bat\":2 }], { \"apple\": 1, \"bat\": 2 }) should return [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }].", - "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, {\"bat\":2}], { \"apple\": 1, \"bat\": 2 }), [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, { \"bat\":2 }], { \"apple\": 1, \"bat\": 2 }) should return [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }].');" + "text": "whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, { \"bat\":2 }], { \"apple\": 1, \"bat\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }]。", + "testString": "assert.deepEqual(whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, {\"bat\":2}], { \"apple\": 1, \"bat\": 2 }), [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }], 'whatIsInAName([{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1 }, { \"apple\": 1, \"bat\": 2, \"cookie\": 2 }, { \"bat\":2 }], { \"apple\": 1, \"bat\": 2 }) 应该返回 [{ \"apple\": 1, \"bat\": 2 }, { \"apple\": 1, \"bat\": 2, \"cookie\":2 }]。');" }, { - "text": "whatIsInAName([{\"a\": 1, \"b\": 2, \"c\": 3}], {\"a\": 1, \"b\": 9999, \"c\": 3}) should return []", - "testString": "assert.deepEqual(whatIsInAName([{ \"a\": 1, \"b\": 2, \"c\": 3 }], { \"a\": 1, \"b\": 9999, \"c\": 3 }), [], 'whatIsInAName([{\"a\": 1, \"b\": 2, \"c\": 3}], {\"a\": 1, \"b\": 9999, \"c\": 3}) should return []');" + "text": "whatIsInAName([{\"a\": 1, \"b\": 2, \"c\": 3}], {\"a\": 1, \"b\": 9999, \"c\": 3}) 应该返回 []。", + "testString": "assert.deepEqual(whatIsInAName([{ \"a\": 1, \"b\": 2, \"c\": 3 }], { \"a\": 1, \"b\": 9999, \"c\": 3 }), [], 'whatIsInAName([{\"a\": 1, \"b\": 2, \"c\": 3}], {\"a\": 1, \"b\": 9999, \"c\": 3}) 应该返回 []。');" } ], "MDNlinks": [ @@ -281,10 +281,10 @@ "function whatIsInAName(collection, source) {", " // What's in a name?", " var arr = [];", - " // Only change code below this line", + " // 请把你的代码写在这条注释以下", " ", " ", - " // Only change code above this line", + " // 请把你的代码写在这条注释以上", " return arr;", "}", "", @@ -299,32 +299,32 @@ "id": "a103376db3ba46b2d50db289", "title": "Spinal Tap Case", "description": [ - "Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个函数,把一个字符串转换为“短线连接格式”。短线连接格式的意思是,所有字母都是小写,且用 - 连接。比如,对于 Hello World,应该转换为 hello-world;对于 I love_Javascript-VeryMuch,应该转换为 i-love-javascript-very-much。", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}" ], "tests": [ { - "text": "spinalCase(\"This Is Spinal Tap\") should return \"this-is-spinal-tap\".", - "testString": "assert.deepEqual(spinalCase(\"This Is Spinal Tap\"), \"this-is-spinal-tap\", 'spinalCase(\"This Is Spinal Tap\") should return \"this-is-spinal-tap\".');" + "text": "spinalCase(\"This Is Spinal Tap\") 应该返回 \"this-is-spinal-tap\"。", + "testString": "assert.deepEqual(spinalCase(\"This Is Spinal Tap\"), \"this-is-spinal-tap\", 'spinalCase(\"This Is Spinal Tap\") 应该返回 \"this-is-spinal-tap\"。');" }, { - "text": "spinalCase(\"thisIsSpinalTap\") should return \"this-is-spinal-tap\".", - "testString": "assert.strictEqual(spinalCase('thisIsSpinalTap'), \"this-is-spinal-tap\", 'spinalCase(\"thisIsSpinalTap\") should return \"this-is-spinal-tap\".');" + "text": "spinalCase(\"thisIsSpinalTap\") 应该返回 \"this-is-spinal-tap\"。", + "testString": "assert.strictEqual(spinalCase('thisIsSpinalTap'), \"this-is-spinal-tap\", 'spinalCase(\"thisIsSpinalTap\") 应该返回 \"this-is-spinal-tap\"。');" }, { - "text": "spinalCase(\"The_Andy_Griffith_Show\") should return \"the-andy-griffith-show\".", - "testString": "assert.strictEqual(spinalCase(\"The_Andy_Griffith_Show\"), \"the-andy-griffith-show\", 'spinalCase(\"The_Andy_Griffith_Show\") should return \"the-andy-griffith-show\".');" + "text": "spinalCase(\"The_Andy_Griffith_Show\") 应该返回 \"the-andy-griffith-show\"。", + "testString": "assert.strictEqual(spinalCase(\"The_Andy_Griffith_Show\"), \"the-andy-griffith-show\", 'spinalCase(\"The_Andy_Griffith_Show\") 应该返回 \"the-andy-griffith-show\"。');" }, { - "text": "spinalCase(\"Teletubbies say Eh-oh\") should return \"teletubbies-say-eh-oh\".", - "testString": "assert.strictEqual(spinalCase(\"Teletubbies say Eh-oh\"), \"teletubbies-say-eh-oh\", 'spinalCase(\"Teletubbies say Eh-oh\") should return \"teletubbies-say-eh-oh\".');" + "text": "spinalCase(\"Teletubbies say Eh-oh\") 应该返回 \"teletubbies-say-eh-oh\"。", + "testString": "assert.strictEqual(spinalCase(\"Teletubbies say Eh-oh\"), \"teletubbies-say-eh-oh\", 'spinalCase(\"Teletubbies say Eh-oh\") 应该返回 \"teletubbies-say-eh-oh\"。');" }, { - "text": "spinalCase(\"AllThe-small Things\") should return \"all-the-small-things\".", - "testString": "assert.strictEqual(spinalCase(\"AllThe-small Things\"), \"all-the-small-things\", 'spinalCase(\"AllThe-small Things\") should return \"all-the-small-things\".');" + "text": "spinalCase(\"AllThe-small Things\") 应该返回 \"all-the-small-things\"。", + "testString": "assert.strictEqual(spinalCase(\"AllThe-small Things\"), \"all-the-small-things\", 'spinalCase(\"AllThe-small Things\") 应该返回 \"all-the-small-things\"。');" } ], "MDNlinks": [ @@ -340,8 +340,7 @@ "name": "index", "contents": [ "function spinalCase(str) {", - " // \"It's such a fine line between stupid, and clever.\"", - " // --David St. Hubbins", + "", " return str;", "}", "", @@ -356,43 +355,43 @@ "id": "aa7697ea2477d1316795783b", "title": "Pig Latin", "description": [ - "Translate the provided string to pig latin.", - "Pig Latin takes the first consonant (or consonant cluster) of an English word, moves it to the end of the word and suffixes an \"ay\".", - "If a word begins with a vowel you just add \"way\" to the end.", - "Input strings are guaranteed to be English words in all lowercase.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个函数,把传入的字符串翻译成“儿童黑话”。", + "儿童黑话的基本转换规则很简单,只需要把一个英文单词的第一个辅音字母或第一组辅音从移到单词的结尾,并在后面加上 ay 即可。在英语中,字母 a、e、i、o、u 为元音,其余的字母均为辅音。辅音从的意思是连续的多个辅音字母。", + "额外地,如果单词本身是以元音开头的,那只需要在结尾加上 way。", + "在本题中,传入的单词一定会是英文单词,且所有字母均为小写。", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function translatePigLatin(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}" ], "tests": [ { - "text": "translatePigLatin(\"california\") should return \"aliforniacay\".", - "testString": "assert.deepEqual(translatePigLatin(\"california\"), \"aliforniacay\", 'translatePigLatin(\"california\") should return \"aliforniacay\".');" + "text": "translatePigLatin(\"california\") 应该返回 \"aliforniacay\"。", + "testString": "assert.deepEqual(translatePigLatin(\"california\"), \"aliforniacay\", 'translatePigLatin(\"california\") 应该返回 \"aliforniacay\"。');" }, { - "text": "translatePigLatin(\"paragraphs\") should return \"aragraphspay\".", - "testString": "assert.deepEqual(translatePigLatin(\"paragraphs\"), \"aragraphspay\", 'translatePigLatin(\"paragraphs\") should return \"aragraphspay\".');" + "text": "translatePigLatin(\"paragraphs\") 应该返回 \"aragraphspay\"。", + "testString": "assert.deepEqual(translatePigLatin(\"paragraphs\"), \"aragraphspay\", 'translatePigLatin(\"paragraphs\") 应该返回 \"aragraphspay\"。');" }, { - "text": "translatePigLatin(\"glove\") should return \"oveglay\".", - "testString": "assert.deepEqual(translatePigLatin(\"glove\"), \"oveglay\", 'translatePigLatin(\"glove\") should return \"oveglay\".');" + "text": "translatePigLatin(\"glove\") 应该返回 \"oveglay\"。", + "testString": "assert.deepEqual(translatePigLatin(\"glove\"), \"oveglay\", 'translatePigLatin(\"glove\") 应该返回 \"oveglay\"。');" }, { - "text": "translatePigLatin(\"algorithm\") should return \"algorithmway\".", - "testString": "assert.deepEqual(translatePigLatin(\"algorithm\"), \"algorithmway\", 'translatePigLatin(\"algorithm\") should return \"algorithmway\".');" + "text": "translatePigLatin(\"algorithm\") 应该返回 \"algorithmway\"。", + "testString": "assert.deepEqual(translatePigLatin(\"algorithm\"), \"algorithmway\", 'translatePigLatin(\"algorithm\") 应该返回 \"algorithmway\"。');" }, { - "text": "translatePigLatin(\"eight\") should return \"eightway\".", - "testString": "assert.deepEqual(translatePigLatin(\"eight\"), \"eightway\", 'translatePigLatin(\"eight\") should return \"eightway\".');" + "text": "translatePigLatin(\"eight\") 应该返回 \"eightway\"。", + "testString": "assert.deepEqual(translatePigLatin(\"eight\"), \"eightway\", 'translatePigLatin(\"eight\") 应该返回 \"eightway\"。');" }, { - "text": "Should handle words where the first vowel comes in the end of the word.", - "testString": "assert.deepEqual(translatePigLatin(\"schwartz\"), \"artzschway\", 'Should handle words where the first vowel comes in the end of the word.');" + "text": "你的代码应当能够处理第一个元音字母在单词结尾的情况。比如 translatePigLatin(\"she\") 应该返回 \"eshay\"。", + "testString": "assert.deepEqual(translatePigLatin(\"she\"), \"eshay\", '你的代码应当能够处理第一个元音字母在单词结尾的情况。比如 translatePigLatin(\"she\") 应该返回 \"eshay\"。');" }, { - "text": "Should handle words without vowels.", - "testString": "assert.deepEqual(translatePigLatin(\"rhythm\"), \"rhythmay\", 'Should handle words without vowels.');" + "text": "你的代码应当能够处理单词中不含元音字母的情况。比如 translatePigLatin(\"rhythm\") 应该返回 \"rhythmay\"。", + "testString": "assert.deepEqual(translatePigLatin(\"rhythm\"), \"rhythmay\", '你的代码应当能够处理单词中不含元音字母的情况。比如 translatePigLatin(\"rhythm\") 应该返回 \"rhythmay\"。');" } ], "MDNlinks": [ @@ -425,36 +424,36 @@ "id": "a0b5010f579e69b815e7c5d6", "title": "Search and Replace", "description": [ - "Perform a search and replace on the sentence using the arguments provided and return the new sentence.", - "First argument is the sentence to perform the search and replace on.", - "Second argument is the word that you will be replacing (before).", - "Third argument is what you will be replacing the second argument with (after).", - "Note
Preserve the case of the first character in the original word when you are replacing it. For example if you mean to replace the word \"Book\" with the word \"dog\", it should be replaced as \"Dog\"", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个字符串的搜索与替换函数,它的返回值为完成替换后的新字符串。", + "这个函数接收的第一个参数为待替换的句子。", + "第二个参数为句中需要被替换的单词。", + "第三个参数为替换后的单词。", + "注意:
你需要保留被替换单词首字母的大小写格式。即如果传入的第二个参数为 \"Book\",第三个参数为 \"dog\",那么替换后的结果应为 \"Dog\"", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function myReplace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}" ], "tests": [ { - "text": "myReplace(\"Let us go to the store\", \"store\", \"mall\") should return \"Let us go to the mall\".", - "testString": "assert.deepEqual(myReplace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", 'myReplace(\"Let us go to the store\", \"store\", \"mall\") should return \"Let us go to the mall\".');" + "text": "myReplace(\"Let us go to the store\", \"store\", \"mall\") 应该返回 \"Let us go to the mall\"。", + "testString": "assert.deepEqual(myReplace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", 'myReplace(\"Let us go to the store\", \"store\", \"mall\") 应该返回 \"Let us go to the mall\"。');" }, { - "text": "myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\") should return \"He is Sitting on the couch\".", - "testString": "assert.deepEqual(myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", 'myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\") should return \"He is Sitting on the couch\".');" + "text": "myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\") 应该返回 \"He is Sitting on the couch\"。", + "testString": "assert.deepEqual(myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", 'myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\") 应该返回 \"He is Sitting on the couch\"。');" }, { - "text": "myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\") should return \"This has a spelling error\".", - "testString": "assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\") should return \"This has a spelling error\".');" + "text": "myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\") 应该返回 \"This has a spelling error\"。", + "testString": "assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\") 应该返回 \"This has a spelling error\"。');" }, { - "text": "myReplace(\"His name is Tom\", \"Tom\", \"john\") should return \"His name is John\".", - "testString": "assert.deepEqual(myReplace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", 'myReplace(\"His name is Tom\", \"Tom\", \"john\") should return \"His name is John\".');" + "text": "myReplace(\"His name is Tom\", \"Tom\", \"john\") 应该返回 \"His name is John\"。", + "testString": "assert.deepEqual(myReplace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", 'myReplace(\"His name is Tom\", \"Tom\", \"john\") 应该返回 \"His name is John\"。');" }, { - "text": "myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\") should return \"Let us get back to more Algorithms\".", - "testString": "assert.deepEqual(myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\"), \"Let us get back to more Algorithms\", 'myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\") should return \"Let us get back to more Algorithms\".');" + "text": "myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\") 应该返回 \"Let us get back to more Algorithms\"。", + "testString": "assert.deepEqual(myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\"), \"Let us get back to more Algorithms\", 'myReplace(\"Let us get back to more Coding\", \"Coding\", \"algorithms\") 应该返回 \"Let us get back to more Algorithms\"。');" } ], "MDNlinks": [ @@ -485,28 +484,27 @@ "id": "afd15382cdfb22c9efe8b7de", "title": "DNA Pairing", "description": [ - "The DNA strand is missing the pairing element. Take each character, get its pair, and return the results as a 2d array.", - "Base pairs are a pair of AT and CG. Match the missing element to the provided character.", - "Return the provided character as the first element in each array.", - "For example, for the input GCG, return [[\"G\", \"C\"], [\"C\",\"G\"],[\"G\", \"C\"]]", - "The character and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个函数,为 DNA 中的碱基配对。这个函数只接收一个表示碱基的字符串为参数,最后返回完成配对的二维数组。", + "碱基对 由一对碱基组成。碱基有四种,分别为 A(腺嘌呤)、T(胸腺嘧啶)、G(鸟嘌呤)和 C(胞嘧啶)。配对原则是:A 与 T 配对,C 与 G 配对。我们需要根据这个原则对传入的所有碱基进行配对。", + "对于每个传入的碱基,我们应采用数组的形式展示配对结果。其中,传入的碱基需要作为数组的第一个元素出现。最终返回的数组中应当包含参数中每一个碱基的配对结果。", + "比如,传入的参数是 GCG,那么函数的返回值应为 [[\"G\", \"C\"], [\"C\",\"G\"],[\"G\", \"C\"]]", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pairElement(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}" ], "tests": [ { - "text": "pairElement(\"ATCGA\") should return [[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]].", - "testString": "assert.deepEqual(pairElement(\"ATCGA\"),[[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]], 'pairElement(\"ATCGA\") should return [[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]].');" + "text": "pairElement(\"ATCGA\") 应该返回 [[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]]。", + "testString": "assert.deepEqual(pairElement(\"ATCGA\"),[[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]], 'pairElement(\"ATCGA\") 应该返回 [[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]]。');" }, { - "text": "pairElement(\"TTGAG\") should return [[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]].", - "testString": "assert.deepEqual(pairElement(\"TTGAG\"),[[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]], 'pairElement(\"TTGAG\") should return [[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]].');" + "text": "pairElement(\"TTGAG\") 应该返回 [[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]]。", + "testString": "assert.deepEqual(pairElement(\"TTGAG\"),[[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]], 'pairElement(\"TTGAG\") 应该返回 [[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]]。');" }, { - "text": "pairElement(\"CTCTA\") should return [[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]].", - "testString": "assert.deepEqual(pairElement(\"CTCTA\"),[[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]], 'pairElement(\"CTCTA\") should return [[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]].');" + "text": "pairElement(\"CTCTA\") 应该返回 [[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]]。", + "testString": "assert.deepEqual(pairElement(\"CTCTA\"),[[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]], 'pairElement(\"CTCTA\") 应该返回 [[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]]。');" } ], "MDNlinks": [ @@ -536,33 +534,33 @@ "id": "af7588ade1100bde429baf20", "title": "Missing letters", "description": [ - "Find the missing letter in the passed letter range and return it.", - "If all letters are present in the range, return undefined.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个函数,找到传入的字符串里缺失的字母并返回它。", + "判断缺失的依据是字母顺序,比如 abcdfg 中缺失了 e。而 abcdef 中就没有字母缺失,此时我们需要返回 undefined。", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function fearNotLetter (str) {\n for (var i = str.charCodeAt(0); i <= str.charCodeAt(str.length - 1); i++) {\n var letter = String.fromCharCode(i);\n if (str.indexOf(letter) === -1) {\n return letter;\n }\n }\n \n return undefined;\n}" ], "tests": [ { - "text": "fearNotLetter(\"abce\") should return \"d\".", - "testString": "assert.deepEqual(fearNotLetter('abce'), 'd', 'fearNotLetter(\"abce\") should return \"d\".');" + "text": "fearNotLetter(\"abce\") 应该返回 \"d\"。", + "testString": "assert.deepEqual(fearNotLetter('abce'), 'd', 'fearNotLetter(\"abce\") 应该返回 \"d\"。');" }, { - "text": "fearNotLetter(\"abcdefghjklmno\") should return \"i\".", - "testString": "assert.deepEqual(fearNotLetter('abcdefghjklmno'), 'i', 'fearNotLetter(\"abcdefghjklmno\") should return \"i\".');" + "text": "fearNotLetter(\"abcdefghjklmno\") 应该返回 \"i\"。", + "testString": "assert.deepEqual(fearNotLetter('abcdefghjklmno'), 'i', 'fearNotLetter(\"abcdefghjklmno\") 应该返回 \"i\"。');" }, { - "text": "fearNotLetter(\"stvwx\") should return \"u\".", - "testString": "assert.deepEqual(fearNotLetter('stvwx'), 'u', 'fearNotLetter(\"stvwx\") should return \"u\".');" + "text": "fearNotLetter(\"stvwx\") 应该返回 \"u\"。", + "testString": "assert.deepEqual(fearNotLetter('stvwx'), 'u', 'fearNotLetter(\"stvwx\") 应该返回 \"u\"。');" }, { - "text": "fearNotLetter(\"bcdf\") should return \"e\".", - "testString": "assert.deepEqual(fearNotLetter('bcdf'), 'e', 'fearNotLetter(\"bcdf\") should return \"e\".');" + "text": "fearNotLetter(\"bcdf\") 应该返回 \"e\"。", + "testString": "assert.deepEqual(fearNotLetter('bcdf'), 'e', 'fearNotLetter(\"bcdf\") 应该返回 \"e\"。');" }, { - "text": "fearNotLetter(\"abcdefghijklmnopqrstuvwxyz\") should return undefined.", - "testString": "assert.isUndefined(fearNotLetter('abcdefghijklmnopqrstuvwxyz'), 'fearNotLetter(\"abcdefghijklmnopqrstuvwxyz\") should return undefined.');" + "text": "fearNotLetter(\"abcdefghijklmnopqrstuvwxyz\") 应该返回 undefined。", + "testString": "assert.isUndefined(fearNotLetter('abcdefghijklmnopqrstuvwxyz'), 'fearNotLetter(\"abcdefghijklmnopqrstuvwxyz\") 应该返回 undefined。');" } ], "MDNlinks": [ @@ -592,31 +590,30 @@ "id": "a105e963526e7de52b219be9", "title": "Sorted Union", "description": [ - "Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays.", - "In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array.", - "The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.", - "Check the assertion tests for examples.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个函数,它接收两个或多个数组为参数。我们需要对这些数组中所有元素进行去除重复元素的处理,并以数组的形式返回去重结果。", + "需要注意的是,结果数组中的元素顺序必须与其传入的顺序保持一致。", + "如有疑问,请先浏览下方的测试用例。", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "function uniteUnique(arr) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}" ], "tests": [ { - "text": "uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) should return [1, 3, 2, 5, 4].", - "testString": "assert.deepEqual(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) should return [1, 3, 2, 5, 4].');" + "text": "uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) 应该返回 [1, 3, 2, 5, 4]。", + "testString": "assert.deepEqual(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) 应该返回 [1, 3, 2, 5, 4]。');" }, { - "text": "uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) should return [1, 3, 2, [5], [4]].", - "testString": "assert.deepEqual(uniteUnique([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) should return [1, 3, 2, [5], [4]].');" + "text": "uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) 应该返回 [1, 3, 2, [5], [4]]。", + "testString": "assert.deepEqual(uniteUnique([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) 应该返回 [1, 3, 2, [5], [4]]。');" }, { - "text": "uniteUnique([1, 2, 3], [5, 2, 1]) should return [1, 2, 3, 5].", - "testString": "assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5], 'uniteUnique([1, 2, 3], [5, 2, 1]) should return [1, 2, 3, 5].');" + "text": "uniteUnique([1, 2, 3], [5, 2, 1]) 应该返回 [1, 2, 3, 5]。", + "testString": "assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5], 'uniteUnique([1, 2, 3], [5, 2, 1]) 应该返回 [1, 2, 3, 5]。');" }, { - "text": "uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) should return [1, 2, 3, 5, 4, 6, 7, 8].", - "testString": "assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [1, 2, 3, 5, 4, 6, 7, 8], 'uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) should return [1, 2, 3, 5, 4, 6, 7, 8].');" + "text": "uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) 应该返回 [1, 2, 3, 5, 4, 6, 7, 8]。", + "testString": "assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [1, 2, 3, 5, 4, 6, 7, 8], 'uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) 应该返回 [1, 2, 3, 5, 4, 6, 7, 8]。');" } ], "MDNlinks": [ @@ -646,40 +643,40 @@ "id": "a6b0bb188d873cb2c8729495", "title": "Convert HTML Entities", "description": [ - "Convert the characters &, <, >, \" (double quote), and ' (apostrophe), in a string to their corresponding HTML entities.", - "Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code." + "在这道题目中,我们需要写一个转换 HTML entity 的函数。需要转换的 HTML entity 有 &<>\"(双引号)和 '(单引号)。转换的规则你可以在 W3C 官网找到。", + "如果你遇到了问题,请点击 帮助。" ], "solutions": [ "var MAP = { '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''};\n\nfunction convertHTML(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}" ], "tests": [ { - "text": "convertHTML(\"Dolce & Gabbana\") should return Dolce &​amp; Gabbana.", - "testString": "assert.match(convertHTML(\"Dolce & Gabbana\"), /Dolce & Gabbana/, 'convertHTML(\"Dolce & Gabbana\") should return Dolce &​amp; Gabbana.');" + "text": "convertHTML(\"Dolce & Gabbana\") 应该返回 Dolce &​amp; Gabbana。", + "testString": "assert.match(convertHTML(\"Dolce & Gabbana\"), /Dolce & Gabbana/, 'convertHTML(\"Dolce & Gabbana\") 应该返回 Dolce &​amp; Gabbana。');" }, { - "text": "convertHTML(\"Hamburgers < Pizza < Tacos\") should return Hamburgers &​lt; Pizza &​lt; Tacos.", - "testString": "assert.match(convertHTML(\"Hamburgers < Pizza < Tacos\"), /Hamburgers < Pizza < Tacos/, 'convertHTML(\"Hamburgers < Pizza < Tacos\") should return Hamburgers &​lt; Pizza &​lt; Tacos.');" + "text": "convertHTML(\"Hamburgers < Pizza < Tacos\") 应该返回 Hamburgers &​lt; Pizza &​lt; Tacos。", + "testString": "assert.match(convertHTML(\"Hamburgers < Pizza < Tacos\"), /Hamburgers < Pizza < Tacos/, 'convertHTML(\"Hamburgers < Pizza < Tacos\") 应该返回 Hamburgers &​lt; Pizza &​lt; Tacos。');" }, { - "text": "convertHTML(\"Sixty > twelve\") should return Sixty &​gt; twelve.", - "testString": "assert.match(convertHTML(\"Sixty > twelve\"), /Sixty > twelve/, 'convertHTML(\"Sixty > twelve\") should return Sixty &​gt; twelve.');" + "text": "convertHTML(\"Sixty > twelve\") 应该返回 Sixty &​gt; twelve。", + "testString": "assert.match(convertHTML(\"Sixty > twelve\"), /Sixty > twelve/, 'convertHTML(\"Sixty > twelve\") 应该返回 Sixty &​gt; twelve。');" }, { - "text": "convertHTML('Stuff in \"quotation marks\"') should return Stuff in &​quot;quotation marks&​quot;.", - "testString": "assert.match(convertHTML('Stuff in \"quotation marks\"'), /Stuff in "quotation marks"/, 'convertHTML('Stuff in \"quotation marks\"') should return Stuff in &​quot;quotation marks&​quot;.');" + "text": "convertHTML('Stuff in \"quotation marks\"') 应该返回 Stuff in &​quot;quotation marks&​quot;。", + "testString": "assert.match(convertHTML('Stuff in \"quotation marks\"'), /Stuff in "quotation marks"/, 'convertHTML('Stuff in \"quotation marks\"') 应该返回 Stuff in &​quot;quotation marks&​quot;。');" }, { - "text": "convertHTML(\"Schindler's List\") should return Schindler&​apos;s List.", - "testString": "assert.match(convertHTML(\"Schindler's List\"), /Schindler's List/, 'convertHTML(\"Schindler's List\") should return Schindler&​apos;s List.');" + "text": "convertHTML(\"Schindler's List\") 应该返回 Schindler&​apos;s List。", + "testString": "assert.match(convertHTML(\"Schindler's List\"), /Schindler's List/, 'convertHTML(\"Schindler's List\") 应该返回 Schindler&​apos;s List。');" }, { - "text": "convertHTML(\"<>\") should return &​lt;&​gt;.", - "testString": "assert.match(convertHTML('<>'), /<>/, 'convertHTML(\"<>\") should return &​lt;&​gt;.');" + "text": "convertHTML(\"<>\") 应该返回 &​lt;&​gt;。", + "testString": "assert.match(convertHTML('<>'), /<>/, 'convertHTML(\"<>\") 应该返回 &​lt;&​gt;。');" }, { - "text": "convertHTML(\"abc\") should return abc.", - "testString": "assert.strictEqual(convertHTML('abc'), 'abc', 'convertHTML(\"abc\") should return abc.');" + "text": "convertHTML(\"abc\") 应该返回 abc。", + "testString": "assert.strictEqual(convertHTML('abc'), 'abc', 'convertHTML(\"abc\") 应该返回 abc。');" } ], "MDNlinks": [ @@ -1309,4 +1306,4 @@ } } ] -} \ No newline at end of file +} diff --git a/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.md b/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.md new file mode 100644 index 0000000..5e14193 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting.md @@ -0,0 +1,5 @@ +# Introduction to the Intermediate Algorithm Scripting Challenges # + +This is a stub introduction + +Help us make it real on [GitHub](https://github.com/freeCodeCamp/learn/tree/master/src/introductions). \ No newline at end of file diff --git a/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.md b/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.md new file mode 100644 index 0000000..6123a26 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects.md @@ -0,0 +1,17 @@ +# Introduction to the JavaScript Algorithms and Data Structures Projects # + +Time to put your new JavaScript skills to work! These challenges will be similar to the algorithm scripting challenges but more difficult. This will allow you to prove how much you have learned. + +In this section you will create the following small JavaScript programs: + +* Roman Numeral Converter + +* Caesars Cipher + +* Telephone Number Validator + +* Cash Register + +Have fun and remember to use the Read-Search-Ask method if you get stuck. + +Good Luck! 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 18d0f52..e55e814 100644 --- a/02-javascript-algorithms-and-data-structures/object-oriented-programming.json +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.json @@ -8,27 +8,27 @@ "id": "587d7dac367417b2b2512b73", "title": "Create a Basic JavaScript Object", "description": [ - "Think about things people see everyday, like cars, shops, and birds. These are all objects: tangible things people can observe and interact with.", - "What are some qualities of these objects? A car has wheels. Shops sell items. Birds have wings.", - "These qualities, or properties, define what makes up an object. Note that similar objects share the same properties, but may have different values for those properties. For example, all cars have wheels, but not all cars have the same number of wheels.", - "Objects in JavaScript are used to model real-world objects, giving them properties and behavior just like their real-world counterparts. Here's an example using these concepts to create a duck object:", + "想想我们在生活中每天都可见到的事物:比如汽车、商店以及小鸟等。它们都是物体:即人们可以观察和与之互动的实体事物。", + "那么这些物体都有哪些特征呢?比如汽车的特征是有轮子,商店是用来出售商品的,而小鸟的特征是有翅膀。", + "这些特征,或者说是属性定义了一个物体由什么构成的。需要注意的是:那些相似的物体可以拥有相同的属性,但是这些属性可能会有不同的值。举个例子:所有的汽车都有轮子,但并不是所有汽车的轮子个数都是一样的。", + "JavaScript 中的对象可以用来描述现实世界中的物体,并赋予他们属性和行为,就像它们在现实世界中的对应物一样。下面是使用这些概念来创建一个duck 对象的示例:", "
let duck = {
  name: \"Aflac\",
  numLegs: 2
};
", - "This duck object has two property/value pairs: a name of \"Aflac\" and a numLegs of 2.", + "这个duck 对象 有两组键值对:一个是name属性,它的值是 \"Aflac\";另一个是numLegs属性,它的值是 2。", "
", - "Create a dog object with name and numLegs properties, and set them to a string and a number, respectively." + "创建一个dog 对象,并给这个对象添加两个属性:namenumLegs,同时把这两个属性的值分别设为字符串和数字。" ], "tests": [ { - "text": "dog should be an object.", - "testString": "assert(typeof(dog) === 'object', 'dog should be an object.');" + "text": "dog应该是一个object。", + "testString": "assert(typeof(dog) === 'object', 'dog应该是一个object');" }, { - "text": "dog should have a name property set to a string.", - "testString": "assert(typeof(dog.name) === 'string', 'dog should have a name property set to a string.');" + "text": "dog应该有一个name属性,且它的值是一个字符串。", + "testString": "assert(typeof(dog.name) === 'string', 'dog 应该有一个name属性,且它的值是一个字符串。');" }, { - "text": "dog should have a numLegs property set to a number.", - "testString": "assert(typeof(dog.numLegs) === 'number', 'dog should have a numLegs property set to a number.');" + "text": "dog应该有一个numLegs属性,且它的值是一个数字。", + "testString": "assert(typeof(dog.numLegs) === 'number', 'dog应该有一个numLegs属性,且它的值是一个数字。');" } ], "solutions": [ @@ -56,20 +56,20 @@ "id": "587d7dac367417b2b2512b74", "title": "Use Dot Notation to Access the Properties of an Object", "description": [ - "The last challenge created an object with various properties, now you'll see how to access the values of those properties. Here's an example:", - "
let duck = {
  name: \"Aflac\",
  numLegs: 2
};
console.log(duck.name);
// This prints \"Aflac\" to the console
", - "Dot notation is used on the object name, duck, followed by the name of the property, name, to access the value of \"Aflac\".", + "在上一个挑战中,我们创建了一个拥有不同属性对象,现在我们来看看该如何访问这些属性:", + "
let duck = {
  name: \"Aflac\",
  numLegs: 2
};
console.log(duck.name);
// 这段代码会在控制台中输出 \"Aflac\"
", + "我们可以用“点号表示法”来访问对象的属性,只需要在对象名称后面加上.以及属性名即可。比如,duck.name就可以访问到 \"Aflac\"。", "
", - "Print both properties of the dog object below to your console." + "请在控制台里面输出dog对象中两个属性对应的值。" ], "tests": [ { - "text": "Your should use console.log to print the value for the name property of the dog object.", - "testString": "assert(/console.log\\(.*dog\\.name.*\\)/g.test(code), 'Your should use console.log to print the value for the name property of the dog object.');" + "text": "你应该使用console.log来将dog对象的name属性值输出到控制台。", + "testString": "assert(/console.log\\(.*dog\\.name.*\\)/g.test(code), '你应该使用console.log来将dog对象的name属性值输出到控制台。');" }, { - "text": "Your should use console.log to print the value for the numLegs property of the dog object.", - "testString": "assert(/console.log\\(.*dog\\.numLegs.*\\)/g.test(code), 'Your should use console.log to print the value for the numLegs property of the dog object.');" + "text": "你应该使用console.log来将dog对象的numLegs属性值输出到控制台。", + "testString": "assert(/console.log\\(.*dog\\.numLegs.*\\)/g.test(code), '你应该使用console.log来将dog对象的numLegs属性值输出到控制台。');" } ], "solutions": [ @@ -88,7 +88,7 @@ " name: \"Spot\",", " numLegs: 4", "};", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下 ", "", "" ], @@ -101,22 +101,22 @@ "id": "587d7dad367417b2b2512b75", "title": "Create a Method on an Object", "description": [ - "Objects can have a special type of property, called a method.", - "Methods are properties that are functions. This adds different behavior to an object. Here is the duck example with a method:", - "
let duck = {
  name: \"Aflac\",
  numLegs: 2,
  sayName: function() {return \"The name of this duck is \" + duck.name + \".\";}
};
duck.sayName();
// Returns \"The name of this duck is Aflac.\"
", - "The example adds the sayName method, which is a function that returns a sentence giving the name of the duck.", - "Notice that the method accessed the name property in the return statement using duck.name. The next challenge will cover another way to do this.", + "对象可以有一个叫做方法的特殊属性。", + "方法其实是一个值为函数的属性,它可以为一个对象添加不同的行为。以下就是一个带有方法属性的duck示例:", + "
let duck = {
  name: \"Aflac\",
  numLegs: 2,
  sayName: function() {return \"The name of this duck is \" + duck.name + \".\";}
};
duck.sayName();
// 返回了: \"The name of this duck is Aflac.\"
", + "这个例子给duck对象添加了一个sayName 方法,这个方法返回一个包含duck名字的句子。", + "注意:这个方法在返回语句中使用duck.name的方式来获取name的属性值。在下一个挑战中我们将会使用另外一种方法来实现。", "
", - "Using the dog object, give it a method called sayLegs. The method should return the sentence \"This dog has 4 legs.\"" + "给dog 对象设置一个名为sayLegs的方法,并让它返回 \"This dog has 4 legs.\" 这句话。" ], "tests": [ { - "text": "dog.sayLegs() should be a function.", - "testString": "assert(typeof(dog.sayLegs) === 'function', 'dog.sayLegs() should be a function.');" + "text": "dog.sayLegs()应该是一个函数。", + "testString": "assert(typeof(dog.sayLegs) === 'function', 'dog.sayLegs()应该是一个函数。');" }, { - "text": "dog.sayLegs() should return the given string - note that punctuation and spacing matter.", - "testString": "assert(dog.sayLegs() === 'This dog has 4 legs.', 'dog.sayLegs() should return the given string - note that punctuation and spacing matter.');" + "text": "dog.sayLegs()应该返回给定的字符串,需要注意标点和间距的问题。", + "testString": "assert(dog.sayLegs() === 'This dog has 4 legs.', 'dog.sayLegs()应该返回给定的字符串,需要注意标点和间距的问题。');" } ], "solutions": [ @@ -148,24 +148,24 @@ "id": "587d7dad367417b2b2512b76", "title": "Make Code More Reusable with the this Keyword", "description": [ - "The last challenge introduced a method to the duck object. It used duck.name dot notation to access the value for the name property within the return statement:", + "在上一个挑战中我们了解了该如何给duck对象设置一个方法属性。然后我们通过使用“点号表示法”duck.name来获取name的属性值而不需要使用return语句:", "sayName: function() {return \"The name of this duck is \" + duck.name + \".\";}", - "While this is a valid way to access the object's property, there is a pitfall here. If the variable name changes, any code referencing the original name would need to be updated as well. In a short object definition, it isn't a problem, but if an object has many references to its properties there is a greater chance for error.", - "A way to avoid these issues is with the this keyword:", + "虽然这是访问对象属性的有效方法,但是这里有一个陷阱。如果变量名发生了改变,那么引用了原始名称的任何代码都需要更新。在一个简短的对象定义中这并不是问题,但是如果对象有很多对其属性的引用,那么发生错误的可能性就更大了。", + "我们可以使用this关键字这个方法来避免这一问题:", "
let duck = {
  name: \"Aflac\",
  numLegs: 2,
  sayName: function() {return \"The name of this duck is \" + this.name + \".\";}
};
", - "this is a deep topic, and the above example is only one way to use it. In the current context, this refers to the object that the method is associated with: duck.", - "If the object's name is changed to mallard, it is not necessary to find all the references to duck in the code. It makes the code reusable and easier to read.", + "this是一个很复杂的知识点,而上面那个例子也只是使用this的一种方法而已。在当前的上下文环境中,this指向的就是与这个方法有关联的duck对象。", + "如果把对象的变量名改为mallard,那使用this就没有必要在代码中找到所有指向duck的部分,这样可以使得代码更具有可读性和复用性。", "
", - "Modify the dog.sayLegs method to remove any references to dog. Use the duck example for guidance." + "修改dog.sayLegs方法以将所有直接对dog的引用删除。可以参考上面的例子。" ], "tests": [ { - "text": "dog.sayLegs() should return the given string.", - "testString": "assert(dog.sayLegs() === 'This dog has 4 legs.', 'dog.sayLegs() should return the given string.');" + "text": "dog.sayLegs()应该返回一个指定的字符串。", + "testString": "assert(dog.sayLegs() === 'This dog has 4 legs.', 'dog.sayLegs()应该返回一个指定的字符串。');" }, { - "text": "Your code should use the this keyword to access the numLegs property of dog.", - "testString": "assert(code.match(/this\\.numLegs/g), 'Your code should use the this keyword to access the numLegs property of dog.');" + "text": "你的代码应该使用this关键字来访问dog对象的numLegs属性值。", + "testString": "assert(code.match(/this\\.numLegs/g), '你的代码应该使用this关键字来访问dog对象的numLegs属性值。');" } ], "solutions": [ @@ -197,27 +197,27 @@ "id": "587d7dad367417b2b2512b77", "title": "Define a Constructor Function", "description": [ - "Constructors are functions that create new objects. They define properties and behaviors that will belong to the new object. Think of them as a blueprint for the creation of new objects.", - "Here is an example of a constructor:", + "构造函数用以创建一个新对象,并给这个新对象定义属性和行为。因此这是创建新对象的一个最基本的方式。", + "以下就是一个构造函数的示例:", "
function Bird() {
  this.name = \"Albert\";
  this.color = \"blue\";
  this.numLegs = 2;
}
", - "This constructor defines a Bird object with properties name, color, and numLegs set to Albert, blue, and 2, respectively.", - "Constructors follow a few conventions:", - "
  • Constructors are defined with a capitalized name to distinguish them from other functions that are not constructors.
  • Constructors use the keyword this to set properties of the object they will create. Inside the constructor, this refers to the new object it will create.
  • Constructors define properties and behaviors instead of returning a value as other functions might.
", + "这个构造函数定义了一个Bird对象,其属性namecolornumLegs的值分别被设置为Albertblue和 2。", + "构造函数遵循一些惯例规则:", + "
  • 构造函数函数名的首字母最好大写,这是为了方便我们区分构造函数和其他非构造函数。
  • 构造函数使用this关键字来给它将创建的这个对象设置新的属性。在构造函数里面,this指向的就是它新创建的这个对象。
  • 构造函数定义了属性和行为就可创建对象,而不是像其他函数一样需要设置返回值。
", "
", - "Create a constructor, Dog, with properties name, color, and numLegs that are set to a string, a string, and a number, respectively." + "创建一个构造函数Dog。给其添加namecolornumLegs属性并分别给它们设置为:字符串,字符串和数字。" ], "tests": [ { - "text": "Dog should have a name property set to a string.", - "testString": "assert(typeof (new Dog()).name === 'string', 'Dog should have a name property set to a string.');" + "text": "Dog应该有一个name属性且它的值是一个字符串。", + "testString": "assert(typeof (new Dog()).name === 'string', 'Dog应该有一个name属性且它的值是一个字符串。');" }, { - "text": "Dog should have a color property set to a string.", - "testString": "assert(typeof (new Dog()).color === 'string', 'Dog should have a color property set to a string.');" + "text": "Dog应该有一个color属性且它的值是一个字符串。", + "testString": "assert(typeof (new Dog()).color === 'string', 'Dog应该有一个color属性且它的值是一个字符串。');" }, { - "text": "Dog should have a numLegs property set to a number.", - "testString": "assert(typeof (new Dog()).numLegs === 'number', 'Dog should have a numLegs property set to a number.');" + "text": "Dog应该有一个numLegs属性且它的值是一个数字。", + "testString": "assert(typeof (new Dog()).numLegs === 'number', 'Dog应该有一个numLegs属性且它的值是一个数字。');" } ], "solutions": [ @@ -241,24 +241,24 @@ "id": "587d7dad367417b2b2512b78", "title": "Use a Constructor to Create Objects", "description": [ - "Here's the Bird constructor from the previous challenge:", - "
function Bird() {
  this.name = \"Albert\";
  this.color = \"blue\";
  this.numLegs = 2;
  // \"this\" inside the constructor always refers to the object being created
}

let blueBird = new Bird();
", - "Notice that the new operator is used when calling a constructor. This tells JavaScript to create a new instance of Bird called blueBird. Without the new operator, this inside the constructor would not point to the newly created object, giving unexpected results.", - "Now blueBird has all the properties defined inside the Bird constructor:", + "在上一个挑战中,我们用所学到的知识创建了一个Bird构造函数:", + "
function Bird() {
  this.name = \"Albert\";
  this.color = \"blue\";
  this.numLegs = 2;
  // 构造函数里面的 \"this\" 总是指向新创建的实例。
}

let blueBird = new Bird();
", + "注意:通过构造函数创建对象的时候要使用new操作符。因为只有这样,JavaScript 才知道要给Bird这个构造函数创建一个新的实例blueBird。如果不使用new操作符来新建对象,那么构造函数里面的this就无法指向新创建的这个对象实例,从而产生不可预见的错误。", + "现在blueBird这个实例就继承了Bird这个构造函数的所有属性,如下:", "
blueBird.name; // => Albert
blueBird.color; // => blue
blueBird.numLegs; // => 2
", - "Just like any other object, its properties can be accessed and modified:", + "由构造函数创建的实例也和其他对象一样,它的属性可以被访问和修改:", "
blueBird.name = 'Elvira';
blueBird.name; // => Elvira
", "
", - "Use the Dog constructor from the last lesson to create a new instance of Dog, assigning it to a variable hound." + "使用上一个课时中的Dog构造函数创建一个Dog的新实例,并把它赋值给变量hound。" ], "tests": [ { - "text": "hound should be created using the Dog constructor.", - "testString": "assert(hound instanceof Dog, 'hound should be created using the Dog constructor.');" + "text": "hound应该是通过Dog构造函数来创建的。", + "testString": "assert(hound instanceof Dog, 'hound应该是通过Dog构造函数来创建的。');" }, { - "text": "Your code should use the new operator to create an instance of Dog.", - "testString": "assert(code.match(/new/g), 'Your code should use the new operator to create an instance of Dog.');" + "text": "你的代码中应该使用new操作符来创建Dog构造函数的新实例。", + "testString": "assert(code.match(/new/g), '你的代码中应该使用new操作符来创建Dog构造函数的新实例。');" } ], "solutions": [ @@ -278,7 +278,7 @@ " this.color = \"brown\";", " this.numLegs = 4;", "}", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "" ], @@ -291,36 +291,36 @@ "id": "587d7dae367417b2b2512b79", "title": "Extend Constructors to Receive Arguments", "description": [ - "The Bird and Dog constructors from last challenge worked well. However, notice that all Birds that are created with the Bird constructor are automatically named Albert, are blue in color, and have two legs. What if you want birds with different values for name and color? It's possible to change the properties of each bird manually but that would be a lot of work:", + "上一个挑战中BirdDog构造函数运行得不错。但是,注意到没有:所有通过Bird构造函数创建出来的实例Birds都自动的取名为 Albert,颜色都是蓝色,还都有两条腿。如果你想要新创建出来的小鸟们拥有不同的名字和颜色要怎么办呢?当然,手动的去修改每一个小鸟实例自己的属性也是可以实现的,只是会增加很多无谓的工作量:", "
let swan = new Bird();
swan.name = \"Carlos\";
swan.color = \"white\";
", - "Suppose you were writing a program to keep track of hundreds or even thousands of different birds in an aviary. It would take a lot of time to create all the birds, then change the properties to different values for every one.", - "To more easily create different Bird objects, you can design your Bird constructor to accept parameters:", + "假如你写了一个程序来追踪一个鸟舍里面的几百只甚至几千只不同的小鸟,你将会花费很多时间去创建所有的小鸟实例并给它们的属性一一修改为不同的值。", + "为了减轻创建不同Bird对象的工作量,你可以给你的Bird设置为可以接收参数的构造函数:", "
function Bird(name, color) {
  this.name = name;
  this.color = color;
  this.numLegs = 2;
}
", - "Then pass in the values as arguments to define each unique bird into the Bird constructor:", + "然后将值通过参数的方式传递给Bird构造函数来定义每一个唯一的小鸟实例:", "let cardinal = new Bird(\"Bruce\", \"red\");", - "This gives a new instance of Bird with name and color properties set to Bruce and red, respectively. The numLegs property is still set to 2.", - "The cardinal has these properties:", + "这给Bird的名字和颜色属性分别赋值为 Bruce 和红色提供了另外一种方法。但numLegs属性被默认赋值为 2。", + "cardinal有以下这些属性:", "
cardinal.name // => Bruce
cardinal.color // => red
cardinal.numLegs // => 2
", - "The constructor is more flexible. It's now possible to define the properties for each Bird at the time it is created, which is one way that JavaScript constructors are so useful. They group objects together based on shared characteristics and behavior and define a blueprint that automates their creation.", + "这样一来构造函数就变得很灵活了。现在可以直接定义每个Bird实例在创建时的属性,这是 JavaScript 构造函数非常实用的用法之一。它们根据共同或相似的属性和行为将对象归纳为一组,并能够自动的创建各自实例。", "
", - "Create another Dog constructor. This time, set it up to take the parameters name and color, and have the property numLegs fixed at 4. Then create a new Dog saved in a variable terrier. Pass it two strings as arguments for the name and color properties." + "创建另一个Dog构造函数。这一次,给它设置两个参数:namecolor,同时给numLegs赋值为 4。然后创建一个新Dog实例保存为变量名:terrier,再将两个字符串通过参数的形式传入namecolor属性。" ], "tests": [ { - "text": "Dog should receive an argument for name.", - "testString": "assert((new Dog('Clifford')).name === 'Clifford', 'Dog should receive an argument for name.');" + "text": "Dog应该接收一个name参数。", + "testString": "assert((new Dog('Clifford')).name === 'Clifford', 'Dog应该接收一个name参数。');" }, { - "text": "Dog should receive an argument for color.", - "testString": "assert((new Dog('Clifford', 'yellow')).color === 'yellow', 'Dog should receive an argument for color.');" + "text": "Dog应该接收一个color参数。", + "testString": "assert((new Dog('Clifford', 'yellow')).color === 'yellow', 'Dog应该接收一个color参数。');" }, { - "text": "Dog should have property numLegs set to 4.", - "testString": "assert((new Dog('Clifford')).numLegs === 4, 'Dog should have property numLegs set to 4.');" + "text": "Dog应该有一个numLegs属性且值为 4。", + "testString": "assert((new Dog('Clifford')).numLegs === 4, 'Dog应该有一个numLegs属性且值为 4。');" }, { - "text": "terrier should be created using the Dog constructor.", - "testString": "assert(terrier instanceof Dog, 'terrier should be created using the Dog constructor.');" + "text": "terrier应该是通过Dog构造函数创建的。", + "testString": "assert(terrier instanceof Dog, 'terrier应该是通过Dog构造函数创建的。');" } ], "solutions": [ @@ -350,21 +350,21 @@ "id": "587d7dae367417b2b2512b7a", "title": "Verify an Object's Constructor with instanceof", "description": [ - "Anytime a constructor function creates a new object, that object is said to be an instance of its constructor. JavaScript gives a convenient way to verify this with the instanceof operator. instanceof allows you to compare an object to a constructor, returning true or false based on whether or not that object was created with the constructor. Here's an example:", + "凡是通过构造函数创建出的新对象,都叫做这个构造函数的实例。JavaScript 提供了一种很简便的方法来验证这个事实,那就是通过instanceof操作符。instanceof允许你将对象与构造函数之间进行比较,根据对象是否由这个构造函数创建的返回true或者false。以下是一个示例:", "
let Bird = function(name, color) {
  this.name = name;
  this.color = color;
  this.numLegs = 2;
}

let crow = new Bird(\"Alexis\", \"black\");

crow instanceof Bird; // => true
", - "If an object is created without using a constructor, instanceof will verify that it is not an instance of that constructor:", + "如果一个对象不是使用构造函数创建的,那么instanceof将会验证这个对象不是构造函数的实例:", "
let canary = {
  name: \"Mildred\",
  color: \"Yellow\",
  numLegs: 2
};

canary instanceof Bird; // => false
", "
", - "Create a new instance of the House constructor, calling it myHouse and passing a number of bedrooms. Then, use instanceof to verify that it is an instance of House." + "给House构造函数创建一个新实例,取名为myHouse并且传递一个数字给bedrooms参数。然后使用instanceof操作符验证这个对象是否为House的实例。" ], "tests": [ { - "text": "myHouse should have a numBedrooms attribute set to a number.", - "testString": "assert(typeof myHouse.numBedrooms === 'number', 'myHouse should have a numBedrooms attribute set to a number.');" + "text": "myHouse应该有一个numBedrooms属性被赋值为一个数字。", + "testString": "assert(typeof myHouse.numBedrooms === 'number', 'myHouse应该有一个numBedrooms属性被赋值为一个数字。');" }, { - "text": "Be sure to verify that myHouse is an instance of House using the instanceof operator.", - "testString": "assert(/myHouse\\s*instanceof\\s*House/.test(code), 'Be sure to verify that myHouse is an instance of House using the instanceof operator.');" + "text": "请务必使用instanceof操作符验证myHouse这个对象是House构造函数的一个实例。", + "testString": "assert(/myHouse\\s*instanceof\\s*House/.test(code), '请务必使用instanceof操作符验证myHouse这个对象是House构造函数的一个实例。');" } ], "solutions": [ @@ -385,7 +385,7 @@ " this.numBedrooms = numBedrooms;", "}", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "" @@ -399,23 +399,23 @@ "id": "587d7dae367417b2b2512b7b", "title": "Understand Own Properties", "description": [ - "In the following example, the Bird constructor defines two properties: name and numLegs:", + "请看下面的实例,Bird构造函数定义了两个属性:namenumLegs:", "
function Bird(name) {
  this.name = name;
  this.numLegs = 2;
}

let duck = new Bird(\"Donald\");
let canary = new Bird(\"Tweety\");
", - "name and numLegs are called own properties, because they are defined directly on the instance object. That means that duck and canary each has its own separate copy of these properties.", - "In fact every instance of Bird will have its own copy of these properties.", - "The following code adds all of the own properties of duck to the array ownProps:", + "namenumLegs被叫做自身属性,因为他们是直接在实例对象上定义的。这就意味着duckcanary这两个对象分别拥有这些属性的独立副本。", + "事实上,Bird的这些实例都将拥有这些属性的独立副本。", + "以下的代码将duck里面所有的自身属性都存到一个叫 code>ownProps
的数组里面:", "
let ownProps = [];

for (let property in duck) {
  if(duck.hasOwnProperty(property)) {
    ownProps.push(property);
  }
}

console.log(ownProps); // prints [ \"name\", \"numLegs\" ]
", "
", - "Add the own properties of canary to the array ownProps." + "将canary对象里面的自身属性添加到ownProps数组里面。" ], "tests": [ { - "text": "ownProps should include the values \"numLegs\" and \"name\".", - "testString": "assert(ownProps.indexOf('name') !== -1 && ownProps.indexOf('numLegs') !== -1, 'ownProps should include the values \"numLegs\" and \"name\".');" + "text": "ownProps应该包含\"numLegs\"\"name\"两个属性的值。", + "testString": "assert(ownProps.indexOf('name') !== -1 && ownProps.indexOf('numLegs') !== -1, 'ownProps应该包含\"numLegs\"\"name\"两个属性的值。');" }, { - "text": "Solve this challenge without using the built in method Object.keys().", - "testString": "assert(!/\\Object.keys/.test(code), 'Solve this challenge without using the built in method Object.keys().');" + "text": "在不使用内置方法Object.keys()的情况下完成这个挑战。", + "testString": "assert(!/\\Object.keys/.test(code), '在不使用内置方法Object.keys()的情况下完成这个挑战。');" } ], "solutions": [ @@ -437,7 +437,7 @@ "", "let canary = new Bird(\"Tweety\");", "let ownProps = [];", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "", "", "" @@ -451,29 +451,29 @@ "id": "587d7dae367417b2b2512b7c", "title": "Use Prototype Properties to Reduce Duplicate Code", "description": [ - "Since numLegs will probably have the same value for all instances of Bird, you essentially have a duplicated variable numLegs inside each Bird instance.", - "This may not be an issue when there are only two instances, but imagine if there are millions of instances. That would be a lot of duplicated variables.", - "A better way is to use Bird’s prototype. The prototype is an object that is shared among ALL instances of Bird. Here's how to add numLegs to the Bird prototype:", + "所有Bird实例可能会有相同的numLegs值,所以在每一个Bird的实例中本质上都有一个重复的变量numLegs。", + "当只有两个实例时可能并不是什么问题,但想象一下如果有数百万个实例,这将会产生许许多多重复的变量。", + "这里有一个更好的方法可以解决上述问题,那就是使用Bird原型原型是一个可以在所有Bird实例之间共享的对象。以下是一个在Bird prototype中添加numLegs属性的示例:", "
Bird.prototype.numLegs = 2;
", - "Now all instances of Bird have the numLegs property.", - "
console.log(duck.numLegs); // prints 2
console.log(canary.numLegs); // prints 2
", - "Since all instances automatically have the properties on the prototype, think of a prototype as a \"recipe\" for creating objects.", - "Note that the prototype for duck and canary is part of the Bird constructor as Bird.prototype. Nearly every object in JavaScript has a prototype property which is part of the constructor function that created it.", + "现在所有的Bird实例都拥有了共同的numLegs属性值。", + "
console.log(duck.numLegs); // 在控制台输出 2
console.log(canary.numLegs); // 在控制台输出 2
", + "由于所有的实例都可以继承原型上的属性,所以可以把原型看作是创建对象的 \"配方\"。", + "请注意:duckcanary原型Bird构造函数原型Bird.prototype的一部分。JavaScript 中几乎所有的对象都有一个原型属性,这个属性是属于它所在的构造函数的一部分。", "
", - "Add a numLegs property to the prototype of Dog" + "给Dog原型添加一个numLegs属性。" ], "tests": [ { - "text": "beagle should have a numLegs property.", - "testString": "assert(beagle.numLegs !== undefined, 'beagle should have a numLegs property.');" + "text": "beagle应该有一个numLegs属性。", + "testString": "assert(beagle.numLegs !== undefined, 'beagle应该有一 numLegs属性。');" }, { - "text": "beagle.numLegs should be a number.", - "testString": "assert(typeof(beagle.numLegs) === 'number' , 'beagle.numLegs should be a number.');" + "text": "beagle.numLegs应该是一个数字。", + "testString": "assert(typeof(beagle.numLegs) === 'number' , 'beagle.numLegs应该是一个数字。');" }, { - "text": "numLegs should be a prototype property not an own property.", - "testString": "assert(beagle.hasOwnProperty('numLegs') === false, 'numLegs should be a prototype property not an own property.');" + "text": "numLegs应该是一个原型属性而不是一个自身属性。", + "testString": "assert(beagle.hasOwnProperty('numLegs') === false, 'numLegs应该是一个原型属性而不是一个自身属性。');" } ], "solutions": [ @@ -494,7 +494,7 @@ "", "", "", - "// Add your code above this line", + "// 请把你的代码写在这条注释以下", "let beagle = new Dog(\"Snoopy\");" ], "head": [], @@ -506,25 +506,25 @@ "id": "587d7daf367417b2b2512b7d", "title": "Iterate Over All Properties", "description": [ - "You have now seen two kinds of properties: own properties and prototype properties. Own properties are defined directly on the object instance itself. And prototype properties are defined on the prototype.", - "
function Bird(name) {
  this.name = name; //own property
}

Bird.prototype.numLegs = 2; // prototype property

let duck = new Bird(\"Donald\");
", - "Here is how you add duck’s own properties to the array ownProps and prototype properties to the array prototypeProps:", - "
let ownProps = [];
let prototypeProps = [];

for (let property in duck) {
  if(duck.hasOwnProperty(property)) {
    ownProps.push(property);
  } else {
    prototypeProps.push(property);
  }
}

console.log(ownProps); // prints [\"name\"]
console.log(prototypeProps); // prints [\"numLegs\"]
", + "现在你已经了解了两种属性: 自身属性和原型属性。自身属性是直接在对象上定义的。而原型属性是定义在prototype上的:", + "
function Bird(name) {
  this.name = name; // 自身属性
}

Bird.prototype.numLegs = 2; // 原型属性

let duck = new Bird(\"Donald\");
", + "这个示例会告诉你如何将duck自身属性和原型属性分别添加到ownProps数组和prototypeProps数组里面:", + "
let ownProps = [];
let prototypeProps = [];

for (let property in duck) {
  if(duck.hasOwnProperty(property)) {
    ownProps.push(property);
  } else {
    prototypeProps.push(property);
  }
}

console.log(ownProps); // 输出 [\"name\"]
console.log(prototypeProps); // 输出 [\"numLegs\"]
", "
", - "Add all of the own properties of beagle to the array ownProps. Add all of the prototype properties of Dog to the array prototypeProps." + "将beagle的所有属性都添加到ownProps数组里面去。将Dog的所有原型属性添加到prototypeProps数组中。" ], "tests": [ { - "text": "The ownProps array should include \"name\".", - "testString": "assert(ownProps.indexOf('name') !== -1, 'The ownProps array should include \"name\".');" + "text": "这个ownProps数组应该包含\"name\"这个值。", + "testString": "assert(ownProps.indexOf('name') !== -1, '这个ownProps属性应该包含\"name\"这个值。');" }, { - "text": "The prototypeProps array should include \"numLegs\".", - "testString": "assert(prototypeProps.indexOf('numLegs') !== -1, 'The prototypeProps array should include \"numLegs\".');" + "text": "这个prototypeProps数组应该包含\"numLegs\"这个值。", + "testString": "assert(prototypeProps.indexOf('numLegs') !== -1, '这个prototypeProps数组应该包含\"numLegs\"这个值。');" }, { - "text": "Solve this challenge without using the built in method Object.keys().", - "testString": "assert(!/\\Object.keys/.test(code), 'Solve this challenge without using the built in method Object.keys().');" + "text": "在不使用内置方法Object.keys()的情况下完成这个挑战。", + "testString": "assert(!/\\Object.keys/.test(code), '在不使用内置方法Object.keys()的情况下完成这个挑战。');" } ], "solutions": [ @@ -550,7 +550,7 @@ "let ownProps = [];", "let prototypeProps = [];", "", - "// Add your code below this line ", + "// 请把你的代码写在这条注释以下 ", "", "", "" @@ -564,27 +564,27 @@ "id": "587d7daf367417b2b2512b7e", "title": "Understand the Constructor Property", "description": [ - "There is a special constructor property located on the object instances duck and beagle that were created in the previous challenges:", - "
let duck = new Bird();
let beagle = new Dog();

console.log(duck.constructor === Bird); //prints true
console.log(beagle.constructor === Dog); //prints true
", - "Note that the constructor property is a reference to the constructor function that created the instance.", - "The advantage of the constructor property is that it's possible to check for this property to find out what kind of object it is. Here's an example of how this could be used:", + "在上一个挑战中创建的实例对象duckbeagle都有一个特殊的constructor属性:", + "
let duck = new Bird();
let beagle = new Dog();

console.log(duck.constructor === Bird); //输出 true
console.log(beagle.constructor === Dog); //输出 true
", + "需要注意到的是这个constructor属性是对创建这个实例的构造函数的一个引用。", + "constructor属性存在的一个优势是,我们可以通过检查这个属性来找出它是一个什么样的对象。下面是一个例子,来看看是怎么使用的:", "
function joinBirdFraternity(candidate) {
  if (candidate.constructor === Bird) {
    return true;
  } else {
    return false;
  }
}
", - "Note
Since the constructor property can be overwritten (which will be covered in the next two challenges) it’s generally better to use the instanceof method to check the type of an object.", + "注意:
由于constructor属性可以被重写(在下面两节挑战中将会遇到),所以使用instanceof方法来检查对象的类型会更好。", "
", - "Write a joinDogFraternity function that takes a candidate parameter and, using the constructor property, return true if the candidate is a Dog, otherwise return false." + "写一个joinDogFraternity函数,传入一个candidate参数并使用constructor属性来判断传入的 candidate 是不是Dog创建的对象实例,如果是,就返回true,否则返回false。" ], "tests": [ { - "text": "joinDogFraternity should be defined as a function.", - "testString": "assert(typeof(joinDogFraternity) === 'function', 'joinDogFraternity should be defined as a function.');" + "text": "joinDogFraternity应该被定义为一个函数。", + "testString": "assert(typeof(joinDogFraternity) === 'function', 'joinDogFraternity应该被定义为一个函数。');" }, { - "text": "joinDogFraternity should return true ifcandidate is an instance of Dog.", - "testString": "assert(joinDogFraternity(new Dog(\"\")) === true, 'joinDogFraternity should return true ifcandidate is an instance of Dog.');" + "text": "如果candidateDog的一个对象实例,则joinDogFraternity函数应该返回true。", + "testString": "assert(joinDogFraternity(new Dog(\"\")) === true, '如果candidateDog的一个对象实例,则joinDogFraternity函数应该返回true。');" }, { - "text": "joinDogFraternity should use the constructor property.", - "testString": "assert(/\\.constructor/.test(code) && !/instanceof/.test(code), 'joinDogFraternity should use the constructor property.');" + "text": "joinDogFraternity中应该用到constructor属性。", + "testString": "assert(/\\.constructor/.test(code) && !/instanceof/.test(code), 'joinDogFraternity中应该用到constructor属性。');" } ], "solutions": [ @@ -603,7 +603,7 @@ " this.name = name;", "}", "", - "// Add your code below this line", + "// 请把你的代码写在这条注释以下", "function joinDogFraternity(candidate) {", " ", "}", @@ -618,31 +618,31 @@ "id": "587d7daf367417b2b2512b7f", "title": "Change the Prototype to a New Object", "description": [ - "Up until now you have been adding properties to the prototype individually:", + "到目前为止,你已经可以单独给prototype添加属性了:", "
Bird.prototype.numLegs = 2;
", - "This becomes tedious after more than a few properties.", + "这将在添加许多属性的时候变得单调乏味。", "
Bird.prototype.eat = function() {
  console.log(\"nom nom nom\");
}

Bird.prototype.describe = function() {
  console.log(\"My name is \" + this.name);
}
", - "A more efficient way is to set the prototype to a new object that already contains the properties. This way, the properties are added all at once:", + "一种更有效的方法就是给对象的prototype设置为一个已经包含了属性的新对象。这样一来,所有属性都可以一次性添加进来:", "
Bird.prototype = {
  numLegs: 2,
  eat: function() {
    console.log(\"nom nom nom\");
  },
  describe: function() {
    console.log(\"My name is \" + this.name);
  }
};
", "
", - "Add the property numLegs and the two methods eat() and describe() to the prototype of Dog by setting the prototype to a new object." + "通过给prototype设置为新对象的方法,在Dog构造函数的原型上添加一个属性numLegs以及两个方法:eat()describe()。" ], "tests": [ { - "text": "Dog.prototype should be set to a new object.", - "testString": "assert((/Dog\\.prototype\\s*?=\\s*?{/).test(code), 'Dog.prototype should be set to a new object.');" + "text": "Dog.prototype应该被设置为一个新对象。", + "testString": "assert((/Dog\\.prototype\\s*?=\\s*?{/).test(code), 'Dog.prototype应该被设置为一个新对象。');" }, { - "text": "Dog.prototype should have the property numLegs.", - "testString": "assert(Dog.prototype.numLegs !== undefined, 'Dog.prototype should have the property numLegs.');" + "text": "Dog.prototype应该拥有属性numLegs。", + "testString": "assert(Dog.prototype.numLegs !== undefined, 'Dog.prototype应该拥有属性numLegs。');" }, { - "text": "Dog.prototype should have the method eat().", - "testString": "assert(typeof Dog.prototype.eat === 'function', 'Dog.prototype should have the method eat().'); " + "text": "Dog.prototype应该拥有方法eat()。", + "testString": "assert(typeof Dog.prototype.eat === 'function', 'Dog.prototype应该拥有方法eat()。'); " }, { - "text": "Dog.prototype should have the method describe().", - "testString": "assert(typeof Dog.prototype.describe === 'function', 'Dog.prototype should have the method describe().'); " + "text": "Dog.prototype应该拥有方法describe()。", + "testString": "assert(typeof Dog.prototype.describe === 'function', 'Dog.prototype应该拥有方法describe()。'); " } ], "solutions": [ @@ -662,7 +662,7 @@ "}", "", "Dog.prototype = {", - " // Add your code below this line", + " // 请把你的代码写在这条注释以下", " ", "};" ], @@ -1419,4 +1419,4 @@ } } ] -} \ No newline at end of file +} diff --git a/02-javascript-algorithms-and-data-structures/object-oriented-programming.md b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md new file mode 100644 index 0000000..4918604 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/object-oriented-programming.md @@ -0,0 +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. diff --git a/02-javascript-algorithms-and-data-structures/regular-expressions.md b/02-javascript-algorithms-and-data-structures/regular-expressions.md new file mode 100644 index 0000000..9289429 --- /dev/null +++ b/02-javascript-algorithms-and-data-structures/regular-expressions.md @@ -0,0 +1,3 @@ +# Introduction to the Regular Expression Challenges # + +Regular expressions are special strings that represent a search pattern. Also known as "regex" or "regexp", they help programmers match, search, and replace text. Regular expressions can appear cryptic because a few characters have special meaning. The goal is to combine the symbols and text into a pattern that matches what you want, but only what you want. This section will cover the characters, a few shortcuts, and the common uses for writing regular expressions. diff --git a/03-front-end-libraries/bootstrap.md b/03-front-end-libraries/bootstrap.md new file mode 100644 index 0000000..fe21a10 --- /dev/null +++ b/03-front-end-libraries/bootstrap.md @@ -0,0 +1,11 @@ +# Introduction to the Bootstrap Challenges # + +Bootstrap is a front-end framework used to design responsive web pages and web applications. It takes a mobile-first approach to web development. Bootstrap includes pre-built CSS styles and classes, plus some JavaScript functionality. Bootstrap uses a responsive 12 column grid layout and has design templates for: + +* buttons +* images +* tables +* forms +* navigation + +This section introduces some of the ways to use Bootstrap in your web projects. diff --git a/03-front-end-libraries/data-visualization-projects.md b/03-front-end-libraries/data-visualization-projects.md new file mode 100644 index 0000000..91f9a00 --- /dev/null +++ b/03-front-end-libraries/data-visualization-projects.md @@ -0,0 +1,17 @@ +# Introduction to the Data Visualization Projects # + +This introduction is a stub + +Help us make it real on GitHub. + +# Upcoming Lessons # + +Visualize Data with a Bar Chart + +Visualize Data with a Scatterplot Graph + +Visualize Data with a Heat Map + +Visualize Data with a Choropleth Map + +Visualize Data with a Treemap Diagram \ No newline at end of file diff --git a/03-front-end-libraries/data-visualization-with-d3.md b/03-front-end-libraries/data-visualization-with-d3.md new file mode 100644 index 0000000..6b13e81 --- /dev/null +++ b/03-front-end-libraries/data-visualization-with-d3.md @@ -0,0 +1,7 @@ +# Introduction to the Data Visualization with D3 Challenges # + +D3.js, or D3, stands for Data Driven Documents. D3 is a JavaScript library to create dynamic and interactive data visualizations in the browser. It's built to work with common web standards, namely HTML, CSS, and Scalable Vector Graphics (SVG). + +D3 takes input data and maps it into a visual representation of that data. It supports many different data formats. D3 lets you bind (or attach) the data to the Document Object Model (DOM). You use HTML or SVG elements with D3's built-in methods to transform the data into a visualization. + +D3 gives you a lot of control over the presentation of data. This section covers the basic functionality and how to create visualizations with the D3 library. diff --git a/03-front-end-libraries/front-end-libraries-projects.md b/03-front-end-libraries/front-end-libraries-projects.md new file mode 100644 index 0000000..086d4ed --- /dev/null +++ b/03-front-end-libraries/front-end-libraries-projects.md @@ -0,0 +1,5 @@ +# Introduction to the Front End Libraries Projects # + +This introduction is a stub + +Help us make it real on GitHub. diff --git a/03-front-end-libraries/jquery.md b/03-front-end-libraries/jquery.md new file mode 100644 index 0000000..9036451 --- /dev/null +++ b/03-front-end-libraries/jquery.md @@ -0,0 +1,3 @@ +# Introduction to jQuery # + +jQuery is one of the many libraries for JavaScript. It is designed to simplify scripting done on the client side. jQuery's most recognizable characteristic is its dollar sign ($) syntax. With it, you can easily manipulate elements, create animations and handle input events. diff --git a/03-front-end-libraries/json-apis-and-ajax.md b/03-front-end-libraries/json-apis-and-ajax.md new file mode 100644 index 0000000..8469bae --- /dev/null +++ b/03-front-end-libraries/json-apis-and-ajax.md @@ -0,0 +1,11 @@ +# Introduction to the JSON APIs and AJAX Challenges # + +Similar to how User Interfaces help people use programs, Application Programming Interfaces (APIs) help programs interact with other programs. APIs are tools that computers use to communicate with one another, in part to send and receive data. You can use API functionality in your page once you understand how to make requests and process data from it. Programmers often use AJAX technologies when working with APIs. + +The term AJAX originated as an acronym for Asynchronous JavaScript And XML. It refers to a group of technologies that make asynchronous requests to a server to transfer data, then load any returned data into the page. An asynchronous process has a couple key properties. The browser does not stop loading a page to wait for the server's response. Also, the browser inserts updated data into part of the page without having to refresh the entire page. + +User experience benefits from asynchronous processes in several ways. Pages load faster since the browser isn't waiting for the server to respond in the middle of a page render. Requests and transfers happen in the background, without interrupting what the user is doing. When the browser receives new data, only the necessary area of the page refreshes. These qualities especially enhance the user experience for single page applications. + +The data transferred between the browser and server is often in a format called JavaScript Object Notation (JSON). JSON resembles JavaScript object literal syntax, except that it's transferred as a string. Once received, it can be converted into an object and used in a script. + +This section covers how to transfer and use data using AJAX technologies with a freeCodeCamp API. diff --git a/03-front-end-libraries/react-and-redux.md b/03-front-end-libraries/react-and-redux.md new file mode 100644 index 0000000..5027fdc --- /dev/null +++ b/03-front-end-libraries/react-and-redux.md @@ -0,0 +1,8 @@ +# Introduction to the React and Redux Challenges # + +This series of challenges introduces how to use Redux with React. + +In a React Redux app, you create a single Redux store that manages the state of your entire app. Your React components subscribe to only the pieces of data in the store that are relevant to their role. Then, you dispatch actions directly from React components, which then trigger store updates. + +Improve this intro on GitHub. + diff --git a/03-front-end-libraries/react.md b/03-front-end-libraries/react.md new file mode 100644 index 0000000..6994d97 --- /dev/null +++ b/03-front-end-libraries/react.md @@ -0,0 +1,5 @@ +# Introduction to the React Challenges # + +React, popularized by Facebook, is a open-source JavaScript library for building user interfaces. With JSX, it is used to create components, handle state and props, utilize event listeners and certain life cycle methods to update data as it changes. + +React combines HTML with JavaScript functionality to create its own markup language, JSX. This section will introduce you to all of these concepts and how to implement them for use with your own projects. diff --git a/03-front-end-libraries/redux.md b/03-front-end-libraries/redux.md new file mode 100644 index 0000000..0f6568d --- /dev/null +++ b/03-front-end-libraries/redux.md @@ -0,0 +1,5 @@ +# Introduction to the Redux Challenges # + +Redux is a predictable state container for JavaScript apps. It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. While you can use Redux with any view library, it's introduced here before being combined with React. + +Improve this intro on GitHub. diff --git a/03-front-end-libraries/sass.md b/03-front-end-libraries/sass.md new file mode 100644 index 0000000..e300f6b --- /dev/null +++ b/03-front-end-libraries/sass.md @@ -0,0 +1,11 @@ +# Introduction to the Sass Challenges # + +Sass, or "Syntactically Awesome StyleSheets", is a language extension of CSS. It adds features that aren't available using basic CSS syntax. Sass makes it easier for developers to simplify and maintain the style sheets for their projects. + +Sass can extend the CSS language because it is a preprocessor. It takes code written using Sass syntax, and converts it into basic CSS. This allows you to create variables, nest CSS rules into others, and import other Sass files, among other things. The result is more compact, easier to read code. + +There are two syntaxes available for Sass. The first, known as SCSS (Sassy CSS) and used throughout these challenges, is an extension of the syntax of CSS. This means that every valid CSS stylesheet is a valid SCSS file with the same meaning. Files using this syntax have the .scss extension. + +The second and older syntax, known as the indented syntax (or sometimes just "Sass"), uses indentation rather than brackets to indicate nesting of selectors, and newlines rather than semicolons to separate properties. Files using this syntax have the .sass extension. + +This section introduces the basic features of Sass. diff --git a/04-data-visualization/data-visualization-projects.md b/04-data-visualization/data-visualization-projects.md new file mode 100644 index 0000000..ab8cc32 --- /dev/null +++ b/04-data-visualization/data-visualization-projects.md @@ -0,0 +1,5 @@ +# Introduction to the Data Visualization Projects # + +This introduction is a stub + +Help us make it real on GitHub. diff --git a/04-data-visualization/data-visualization-with-d3.md b/04-data-visualization/data-visualization-with-d3.md new file mode 100644 index 0000000..6b13e81 --- /dev/null +++ b/04-data-visualization/data-visualization-with-d3.md @@ -0,0 +1,7 @@ +# Introduction to the Data Visualization with D3 Challenges # + +D3.js, or D3, stands for Data Driven Documents. D3 is a JavaScript library to create dynamic and interactive data visualizations in the browser. It's built to work with common web standards, namely HTML, CSS, and Scalable Vector Graphics (SVG). + +D3 takes input data and maps it into a visual representation of that data. It supports many different data formats. D3 lets you bind (or attach) the data to the Document Object Model (DOM). You use HTML or SVG elements with D3's built-in methods to transform the data into a visualization. + +D3 gives you a lot of control over the presentation of data. This section covers the basic functionality and how to create visualizations with the D3 library. diff --git a/04-data-visualization/json-apis-and-ajax.md b/04-data-visualization/json-apis-and-ajax.md new file mode 100644 index 0000000..8469bae --- /dev/null +++ b/04-data-visualization/json-apis-and-ajax.md @@ -0,0 +1,11 @@ +# Introduction to the JSON APIs and AJAX Challenges # + +Similar to how User Interfaces help people use programs, Application Programming Interfaces (APIs) help programs interact with other programs. APIs are tools that computers use to communicate with one another, in part to send and receive data. You can use API functionality in your page once you understand how to make requests and process data from it. Programmers often use AJAX technologies when working with APIs. + +The term AJAX originated as an acronym for Asynchronous JavaScript And XML. It refers to a group of technologies that make asynchronous requests to a server to transfer data, then load any returned data into the page. An asynchronous process has a couple key properties. The browser does not stop loading a page to wait for the server's response. Also, the browser inserts updated data into part of the page without having to refresh the entire page. + +User experience benefits from asynchronous processes in several ways. Pages load faster since the browser isn't waiting for the server to respond in the middle of a page render. Requests and transfers happen in the background, without interrupting what the user is doing. When the browser receives new data, only the necessary area of the page refreshes. These qualities especially enhance the user experience for single page applications. + +The data transferred between the browser and server is often in a format called JavaScript Object Notation (JSON). JSON resembles JavaScript object literal syntax, except that it's transferred as a string. Once received, it can be converted into an object and used in a script. + +This section covers how to transfer and use data using AJAX technologies with a freeCodeCamp API. diff --git a/05-apis-and-microservices/apis-and-microservices-projects.md b/05-apis-and-microservices/apis-and-microservices-projects.md new file mode 100644 index 0000000..de93522 --- /dev/null +++ b/05-apis-and-microservices/apis-and-microservices-projects.md @@ -0,0 +1,5 @@ +# Introduction to the APIs and Microservices Projects # + +This introduction is a stub + +Help us make it real on [GitHub](https://github.com/freeCodeCamp/learn/tree/master/src/introductions). diff --git a/05-apis-and-microservices/basic-node-and-express.md b/05-apis-and-microservices/basic-node-and-express.md new file mode 100644 index 0000000..418eb4e --- /dev/null +++ b/05-apis-and-microservices/basic-node-and-express.md @@ -0,0 +1,17 @@ +# Introduction to the Basic Node and Express Challenges # + +Node.js is a JavaScript tool that allows developers to write backend (server-side) programs in JavaScript. Node.js comes with a handful of built-in modules—small, independent programs—that help facilitate this purpose. Some of the core modules include: + + +* HTTP: a module that acts as a server + +* File System: a module that reads and modifies files + +* Path: a module for working with directory and file paths + +8 Assertion Testing: a module that checks code against prescribed constraints + +Express, while not included with Node.js, is another module often used with it. Express runs between the server created by Node.js and the frontend pages of a web application. Express also handles an application's routing. Routing directs users to the correct page based on their interaction with the application. + +While there are alternatives to using Express, its simplicity makes it a good place to begin when learning the interaction between a backend powered by Node.js and the frontend. Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public Glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing. +Start this project on Glitch using this link or clone this repository on GitHub! If you use Glitch, remember to save the link to your project somewhere safe! diff --git a/05-apis-and-microservices/managing-packages-with-npm.json b/05-apis-and-microservices/managing-packages-with-npm.json index 05d6f0f..6b6e589 100644 --- a/05-apis-and-microservices/managing-packages-with-npm.json +++ b/05-apis-and-microservices/managing-packages-with-npm.json @@ -8,21 +8,21 @@ "id": "587d7fb3367417b2b2512bfb", "title": "How to Use package.json, the Core of Any Node.js Project or npm Package", "description": [ - "The file package.json is the center of any Node.js project or npm package. It stores information about your project just like the -section in a HTML document describes the content of a webpage. The package.json consists of a single JSON-object where information is stored in \"key\": value-pairs. There are only two required fields in a minimal package.json - name and version - but it’s a good practice to provide additional information about your project that could be useful to future users or maintainers.", - "The author-field", - "If you go to the Glitch project that you set up previously and look at on the left side of your screen, you’ll find the file tree where you can see an overview of the various files in your project. Under the file tree’s back-end section, you’ll find package.json - the file that we’ll be improving in the next couple of challenges.", - "One of the most common pieces of information in this file is the author-field that specifies who’s the creator of a project. It can either be a string or an object with contact details. The object is recommended for bigger projects but in our case, a simple string like the following example will do.", + "package.json 是任何 Node.js 项目或 npm 包的中心。它存储项目的相关信息,就像 HTML 文档中的 区域是用来描述网页的通用信息(元信息)一样。package.json 由单个 JSON 对象组成,它以键值对的形式存储项目的信息。一个最小的 package.json 文件至少包含两个必须字段:name 和 version——但是提供有关项目的附加信息是一个更好的做法,在以后它可能对你的用户或者维护者有所帮助。", + "author 字段", + "如果你转到之前设置的 Glitch 项目并查看屏幕左侧,你会看到一个文件树,你可以在其中查看项目中各种文件的概述。在文件树的末尾部分,你会看到 package.json——我们将在接下来的几个挑战中改进这个文件。", + "这个文件中最常见的信息之一是 author 字段,它指定了谁是项目的创建者。它可以是字符串,也可以是带有联系人详细信息的对象。对于较大的项目,建议使用对象,但是在我们的例子中,一个简单的字符串就可以了,比如下面的例子。", "\"author\": \"Jane Doe\",", - "Instructions", - "Add your name to the author-field in the package.json of your Glitch project.", - "Remember that you’re writing JSON.", - "All field-names must use double-quotes (\"), e.g. \"author\"", - "All fields must be separated with a comma (,)" + "说明", + "将你的名字添加到 Glitch 项目中,package.json 的 author 字段。", + "请记住,你正在编写 JSON 文件。", + "所有的字段名必须使用双引号(\")包裹, 比如:\"author\"", + "所有字段必须用逗号(,)分隔" ], "tests": [ { - "text": "package.json should have a valid \"author\" key", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.author, '\"author\" is missing'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "package.json 应该有一个有效的 \"author\" 键", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.author, '缺少 \"author\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -33,18 +33,18 @@ "id": "587d7fb3367417b2b2512bfc", "title": "Add a Description to Your package.json", "description": [ - "The next part of a good package.json is the description-field, where a short but informative description about your project belongs.", - "If you some day plan to publishing a package to npm, remember that this is the string that should sell your idea to the user when they decide whether to install your package or not. However, that’s not the only use case for the description: Since it’s a great way to summarize what a project does, it’s just as important for your normal Node.js-projects to help other developers, future maintainers or even your future self understand the project quickly.", - "Regardless of what you plan for your project, a description is definitely recommended. Let’s add something similar to this:", + "一个好的 package.json 文件的下一部分就是 description 字段, 通过简洁的文字来描述你的项目。", + "如果你计划将来把这个包发布到 npm, 请注意 description 字段的作用是告知用户这个包的用途,这样用户就可以决定是否要安装你发布的包。然而,这并不是描述信息的唯一使用场景:它也是一种很好的总结项目的方式,对于一个普通的 Node.js 项目来说,它可以帮助其它开发者、未来的维护者以及你自己快速地了解项目,这同样非常重要。", + "无论你如何计划项目,都建议你使用描述信息。我们来添加类似这样的信息:", "\"description\": \"A project that does something awesome\",", - "Instructions", - "Add a description to the package.json in your Glitch project.", - "Remember to use double-quotes for field-names (\") and commas (,) to separate fields." + "说明", + "在 Glitch 项目的 package.json 中添加描述。", + "请记住使用 (\")包裹字段名并且使用(,)分隔字段" ], "tests": [ { - "text": "package.json should have a valid \"description\" key", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.description, '\"description\" is missing'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "package.json 应该有一个有效的 \"description\" 键", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.description, '缺少 \"description\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -55,26 +55,26 @@ "id": "587d7fb4367417b2b2512bfd", "title": "Add Keywords to Your package.json", "description": [ - "The keywords-field is where you can describe your project using related keywords.", - "Example", + "你可以在 keywords 字段中使用相关的关键字描述项目。", + "例子", "\"keywords\": [ \"descriptive\", \"related\", \"words\" ],", - "As you can see, this field is structured as an array of double-quoted strings.", - "Instructions", - "Add an array of suitable strings to the keywords-field in the package.json of your Glitch project.", - "One of the keywords should be freecodecamp." + "正如你所见,这个字段的结构是一个由双引号字符串组成的数组。", + "说明", + "在 Glitch 项目的 package.json 中,给 keywords 添加适当的字符串数组。", + "关键词之一应该是 freecodecamp。" ], "tests": [ { - "text": "package.json should have a valid \"keywords\" key", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.keywords, '\"keywords\" is missing'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "package.json 应该有一个有效的 \"keywords\" 键", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.keywords, '缺少 \"keywords\"'); }, xhr => { throw new Error(xhr.responseText); })" }, { - "text": "\"keywords\" field should be an Array", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.isArray(packJson.keywords, '\"keywords\" is not an array'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"keywords\" 应该是一个数组", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.isArray(packJson.keywords, '\"keywords\" 不是一个数组'); }, xhr => { throw new Error(xhr.responseText); })" }, { - "text": "\"keywords\" should include \"freecodecamp\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.include(packJson.keywords, 'freecodecamp', '\"keywords\" does not include \"freecodecamp\"'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"keywords\" 中应该包含关键词 \"freecodecamp\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.include(packJson.keywords, 'freecodecamp', '\"keywords\" 未包含 \"freecodecamp\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -85,18 +85,18 @@ "id": "587d7fb4367417b2b2512bfe", "title": "Add a License to Your package.json", "description": [ - "The license-field is where you inform users of your project what they are allowed to do with it.", - "Some common licenses for open source projects include MIT and BSD. http://choosealicense.com is a great resource if you want to learn more about what license could fit your project.", - "License information is not required. Copyright laws in most countries will give you ownership of what you create by default. However, it’s always a good practice to explicitly state what users can and can’t do.", - "Example", + "license 字段是你告知用户允许他们拿这个项目干什么的地方。", + "常见的开源协议是 MIT 和 BSD。如果你想了解更多适合你项目的许可证的信息,那么 http://choosealicense.com 是一个不错的网站。", + "许可证信息并不是必须的。大多数国家的版权法会默认让你拥有自己创作的作品的所有权。但是,明确说明用户可以做什么和不能做什么会是一个很好的做法。", + "例子", "\"license\": \"MIT\",", - "Instructions", - "Fill the license-field in the package.json of your Glitch project as you find suitable." + "说明", + "在 Glitch 项目的 package.json 中填写合适的 license 字段。" ], "tests": [ { - "text": "package.json should have a valid \"license\" key", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.license, '\"license\" is missing'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "package.json 应该有一个有效的 \"license\" 键", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.license, '缺少 \"license\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -107,16 +107,16 @@ "id": "587d7fb4367417b2b2512bff", "title": "Add a Version to Your package.json", "description": [ - "The version is together with name one of the required fields in a package.json. This field describes the current version of your project.", - "Example", + "在 package.json 中 version 和 name 是所必填的字段之一。version 字段描述了当前项目的版本。", + "例子", "\"version\": \"1.2\",", - "Instructions", - "Add a version to the package.json in your Glitch project." + "说明", + "在 Glitch 项目中的 package.json 中添加一个版本号。" ], "tests": [ { - "text": "package.json should have a valid \"version\" key", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.version, '\"version\" is missing'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "package.json 应该包含一个有效的 \"version\" 键", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.version, '缺少 \"version\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -127,24 +127,24 @@ "id": "587d7fb4367417b2b2512c00", "title": "Expand Your Project with External Packages from npm", "description": [ - "One of the biggest reasons to use a package manager is their powerful dependency management. Instead of manually having to make sure that you get all dependencies whenever you set up a project on a new computer, npm automatically installs everything for you. But how can npm know exactly what your project needs? Meet the dependencies-section of your package.json.", - "In the dependencies-section, packages your project require are stored using the following format:", + "使用包管理器的最大原因之一是它们强大的依赖管理特性。在新的计算机上开始一个项目时,不用手动确认你已安装所有的依赖,npm 会自动为你安装它们。但是 npm 如何准确的知道你项目需要哪些依赖呢?我们来看看 package.json 中 dependencies 这一部分。", + "在 dependencies 这一部分,你的项目需要按照下面这种格式来存储这些依赖包:", "\"dependencies\": {", " \"package-name\": \"version\",", " \"express\": \"4.14.0\"", "}", - "Instructions", - "Add version 2.14.0 of the package moment to the dependencies-field of your package.json", - "Moment is a handy library for working with time and dates." + "说明", + "在 package.json 的 dependencies 字段中添加一个版本号为 2.14.0 的 moment 包", + "Moment 是一个非常方便的库,它用来处理时间和日期。" ], "tests": [ { - "text": "\"dependencies\" should include \"moment\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"dependencies\" 应该包含 \"moment\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" 未包含 \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" }, { - "text": "\"moment\" version should be \"2.14.0\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.14\\.0/, 'Wrong version of \"moment\" installed. It should be 2.14.0'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"moment\" 的版本应该是 \"2.14.0\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.14\\.0/, '安装的 \"moment\" 版本有误。它应该是 2.14.0'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -155,29 +155,29 @@ "id": "587d7fb5367417b2b2512c01", "title": "Manage npm Dependencies By Understanding Semantic Versioning", "description": [ - "Versions of the npm packages in the dependencies-section of your package.json follow what’s called Semantic Versioning (SemVer), an industry standard for software versioning aiming to make it easier to manage dependencies. Libraries, frameworks or other tools published on npm should use SemVer in order to clearly communicate what kind of changes that projects who depend on the package can expect if they update.", - "SemVer doesn’t make sense in projects without public APIs - so unless your project is similar to the examples above, use another versioning format.", - "So why do you need to understand SemVer?", - "Knowing SemVer can be useful when you develop software that use external dependencies (which you almost always do). One day, your understanding of these numbers will save you from accidentally introducing breaking changes to your project without understanding why things “that worked yesterday” suddenly doesn’t.", - "This is how Semantic Versioning works according to the official website:", - "Given a version number MAJOR.MINOR.PATCH, increment the:", - "MAJOR version when you make incompatible API changes,", - "MINOR version when you add functionality in a backwards-compatible manner, and", - "PATCH version when you make backwards-compatible bug fixes.", - "This means that PATCHes are bug fixes and MINORs add new features but neither of them break what worked before. Finally, MAJORs add changes that won’t work with earlier versions.", - "Example", - "A semantic version number: 1.3.8", - "Instructions", - "In the dependencies-section of your package.json, change the version of moment to match MAJOR version 2, MINOR version 10 and PATCH version 2" + "在 package.json 中,dependencies 这部分的 npm 包的版本号遵循所谓的语义化版本(SemVer),它是一种软件版本控制的行业标准,旨在使管理依赖项更加容易。在 npm 上发布的库、框架或其它工具都应该使用语义化版本(SemVer),以便让使用该依赖包的用户能够在依赖包需要升级时,提前规划自己的项目需要为之做出的改动。", + "在没有公共 API 的项目中,语义化版本(SemVer)没有意义——除非你的项目与上面的例子类似,否则请使用其它的版本控制方式吧。", + "为什么你需要了解语义化版本(SemVer)?", + "在开发使用外部依赖项的软件(大多数情况都是这样)时,了解语义化版本(SemVer)会很有用。有一天你会明白这些数字的含义,在项目中它可以避免你意外地引入一些非向下兼容的更改,同时也能避免“昨天还能好好的运行,今天就不行了”这种情况发生。", + "根据语义化版本(SemVer)官方网站,它是这样规定的:", + "版本格式:主版本号.次版本号.修订号,版本号递增规则如下:", + "主版本号:当你做了不向下兼容的公共 API 修改,", + "次版本号:当你添加了向下兼容的新功能,", + "修订号:当你做了向下兼容的问题修正。", + "这意味着修订号是用来修复错误的,次版本号则是添加了新功能,但它们都没有破坏之前的功能。最后,主版本号的变更则是添加了对早期版本不兼容的更改。", + "例子", + "一个语义化的版本号:1.3.8", + "说明", + "在 package.json 中,修改 dependencies 里的 moment 的版本号,让它的主版本是 2,次版本号是 10,修订号是 2。" ], "tests": [ { - "text": "\"dependencies\" should include \"moment\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"dependencies\" 应该包含 \"moment\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" 未包含 \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" }, { - "text": "\"moment\" version should be \"2.10.2\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.10\\.2/, 'Wrong version of \"moment\". It should be 2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"moment\" 的版本号应该是 \"2.10.2\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.10\\.2/, '\"moment\" 的版本号有误。它应该是 2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -188,22 +188,22 @@ "id": "587d7fb5367417b2b2512c02", "title": "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency", "description": [ - "In the last challenge, we told npm to only include a specific version of a package. That’s a useful way to freeze your dependencies if you need to make sure that different parts of your project stay compatible with each other. But in most use cases you don’t want to miss bug fixes, since they often include important security patches and (hopefully) don’t break things in doing so.", - "To allow a npm dependency to get updated to the latest PATCH-version, you can prefix the dependency’s version with the tilde-character (~). In package.json, our current rule for how npm may upgrade moment is to use a specific version only (2.10.2), but we want to allow the latest 2.10.x-version.", - "Example", - "\"some-package-name\": \"~1.3.8\" allows updates to any 1.3.x version.", - "Instructions", - "Use the tilde-character (~) to prefix the version of moment in your dependencies and allow npm to update it to any new PATCH release.", - "Note that the version numbers themselves not should be changed." + "在最后一个挑战中,我们告诉 npm 只包含特定版本的依赖包。如果想让项目各个部分保持相互兼容,锁定依赖包版本是一个有效的办法。但是大多数情况下,我们并不希望错过依赖项的问题修复,因为它们通常包含重要的安全补丁,而且它们理论上也会兼容我们既有的代码。", + "为了让 npm 依赖项更新到最新的修订版,你可以在依赖包的版本号前加一个波浪符号(~)。在 package.json 中,我们当前的 moment 依赖包更新规则是:仅使用特定版本(2.10.2),但我们想用它最新的 2.10.x 版本。", + "例子", + "\"some-package-name\": \"~1.3.8\" 定义这个包允许使用的版本为 1.3.x。", + "说明", + "在 dependencies 中,给 moment 的版本号添加波浪符号(~)前缀,允许 npm 将其更新为最新的修订版。", + "请注意,原本的版本号不用更改。" ], "tests": [ { - "text": "\"dependencies\" should include \"moment\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"dependencies\" 应该包含 \"moment\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" 未包含 \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" }, { - "text": "\"moment\" version should match \"~2.10.2\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\~2\\.10\\.2/, 'Wrong version of \"moment\". It should be ~2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"moment\" 的版本号应该是 \"~2.10.2\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\~2\\.10\\.2/, '\"moment\" 版本号有误,它应该是 ~2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -214,22 +214,22 @@ "id": "587d7fb5367417b2b2512c03", "title": "Use the Caret-Character to Use the Latest Minor Version of a Dependency", "description": [ - "Similar to how the tilde (~) we learned about in the last challenge allow npm to install the latest PATCH for a dependency, the caret (^) allows npm to install future updates as well. The difference is that the caret will allow both MINOR updates and PATCHes.", - "At the moment, your current version of moment should be ~2.10.2 which allows npm to install to the latest 2.10.x-version. If we instead were to use the caret (^) as our version prefix, npm would instead be allowed to update to any 2.x.x-version.", - "Example", - "\"some-package-name\": \"^1.3.8\" allows updates to any 1.x.x version.", - "Instructions", - "Use the caret-character (^) to prefix the version of moment in your dependencies and allow npm to update it to any new MINOR release.", - "Note that the version numbers themselves not should be changed." + "和上一个挑战中我们学到的波浪符号(~)来安装最新的修订版依赖一样,使用插入符号(^)允许 npm 来安装功能更新。它们的不同之处在于:插入符号(^)允许次版本和修订版更新。", + "此刻,你项目中的 moment 依赖包的版本应该是 ~2.10.2,这意味着 npm 可以安装 2.10.x 版的 moment,如果使用插入符号(^)来替换版本号的前缀,那么 npm 可以安装的版本则是 2.x.x。", + "例子", + "\"some-package-name\": \"^1.3.8\" 定义这个包允许使用的版本为 1.x.x。", + "说明", + "使用插入符号(^)为依赖项中的 moment 版本添加前缀,允许 npm 更新依赖包到任意向下兼容的新功能版。", + "请注意,原本的版本号不用更改。" ], "tests": [ { "text": "\"dependencies\" should include \"moment\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" 未包含 \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" }, { "text": "\"moment\" version should match \"^2.x.x\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\^2\\./, 'Wrong version of \"moment\". It should be ^2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\^2\\./, '\"moment\" 的版本号有误,它应该是 ^2.10.2'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], @@ -240,17 +240,17 @@ "id": "587d7fb5367417b2b2512c04", "title": "Remove a Package from Your Dependencies", "description": [ - "Now you’ve tested a few ways you can manage dependencies of your project by using the package.json's dependencies-section. You’ve included external packages by adding them to the file and even told npm what types of versions you want by using special characters as the tilde (~) or the caret (^).", - "But what if you want to remove an external package that you no longer need? You might already have guessed it - Just remove the corresponding \"key\": value-pair for that from your dependencies.", - "This same method applies to removing other fields in your package.json as well", - "Instructions", - "Remove the package moment from your dependencies.", - "Make sure you have the right amount of commas after removing it." + "在 package.json 中 dependencies 这一部分,目前尝试了一些管理依赖的方式。你已经添加了一些外部的依赖包到项目中,甚至通过一些特殊的字符比如波浪符号(~)或者插入符号(^)来告诉 npm 你想要的版本类型。", + "但是,如果想要删除不需要的依赖包,该怎么办呢?你可能已经猜到了——只需要删除 dependencies 中的键值对就行了。", + "同样的方法也适用于删除 package.json 中的其它字段", + "说明", + "删除 moment 依赖包。", + "删除依赖包后,确保没有多余的逗号。" ], "tests": [ { - "text": "\"dependencies\" should not include \"moment\"", - "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.notProperty(packJson.dependencies, 'moment', '\"dependencies\" still includes \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" + "text": "\"dependencies\" 不包含 \"moment\"", + "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.notProperty(packJson.dependencies, 'moment', '\"dependencies\" 中仍然有 \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })" } ], "solutions": [], diff --git a/05-apis-and-microservices/managing-packages-with-npm.md b/05-apis-and-microservices/managing-packages-with-npm.md new file mode 100644 index 0000000..1a43f5b --- /dev/null +++ b/05-apis-and-microservices/managing-packages-with-npm.md @@ -0,0 +1,13 @@ +# 挑战简介——使用 npm 管理包 # + +Node 包管理器(npm)是一种命令行工具,开发人员使用它来分享和管理 Node.js 编写的 JavaScript 模块(包)。 + +启动新项目时,npm 会生成一个 package.json 文件。此文件列出了项目的所有依赖。因为依赖包是有规律可循的,package.json 文件允许为每个依赖项设置特定的版本号。以确保这些依赖包更新时不会破坏你的项目。 + +npm 会保存依赖包放入叫 nodemodules 的文件夹内。这些依赖包可以通过两种方式安装: + + +全局安装的依赖包会放在根目录下叫 nodemodules 的文件夹内,以供所有项目使用 +本地安装的依赖包会放在项目内叫 node_modules 的文件夹内,只可以在当前项目使用 + +为了能隔离不同项目之间的依赖,大多数开发者更喜欢在本地项目内安装依赖包。你需要在 Glitch 里启动这个项目并编写相应的代码来应对这些挑战。完成每个挑战后,你可以将 Glitch 地址公开(到你的应用主页)并复制它们,放到挑战题中进行测试!你可以选择另外的平台编写项目代码,但是必须设置为可公开访问,以便我们进行测试。可以使用这个链接在 Glitch 上开始项目,或者克隆这个 GitHub 仓库链接来开始项目!如果你使用 Glitch,请记住将项目链接保存到安全的地方! diff --git a/05-apis-and-microservices/mongodb-and-mongoose.md b/05-apis-and-microservices/mongodb-and-mongoose.md new file mode 100644 index 0000000..cbc0c25 --- /dev/null +++ b/05-apis-and-microservices/mongodb-and-mongoose.md @@ -0,0 +1,77 @@ +# Introduction to the MongoDB and Mongoose Challenges # + +MongoDB is a database that stores data records (documents) for use by an application. Mongo is a non-relational, "NoSQL" database. This means Mongo stores all data associated within one record, instead of storing it across many preset tables as in a SQL database. Some benefits of this storage model are: + +* Scalability: by default, non-relational databases are split (or "sharded") across many systems instead of only one. This makes it easier to improve performance at a lower cost. + +* Flexibility: new datasets and properties can be added to a document without the need to make a new table for that data. + +* Replication: copies of the database run in parallel so if one goes down, one of the copies becomes the new primary data source. + +While there are many non-relational databases, Mongo's use of JSON as its document storage structure makes it a logical choice when learning backend JavaScript. Accessing documents and their properties is like accessing objects in JavaScript. + +Mongoose.js is an npm module for Node.js that allows you to write objects for Mongo as you would in JavaScript. This can make is easier to construct documents for storage in Mongo. + +Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing. + +Start this project on Glitch using this link or clone this repository on GitHub! If you use Glitch, remember to save the link to your project somewhere safe! + +Use mLab to host a free mongodb instance for your projects +For the following challenges, we are going to start using MongoDB to store our data. To simplify the configuration, we are going to use mLab. + +mLab is a MongoDB Database-as-a-Service platform, which basically means that they configure and host the database for you, making it so the only responsibility you have is to populate your database with what matters: data! We are going to show you how to: + +* Create an mLab account. +* Create a free online database. +* Create a new admin user on the database, so you can access it. +* Get the mLab URI, which you will use in your application to connect to your database. +* Create an mLab account +* Let's start by going to mLab. + +Once you open the mLab page, you should sign up for a new account. + +* Click the Sign Up button in the top right corner to open the registration page. +* Fill the registration form with your information and send it. +* You should be logged into your new, unverified account. +* In the top of the screen, a message should appear asking to send you an e-mail for account verification. Send and confirm it. +* After you confirm your account, click Create new in the MongoDB Deployments section. + +# Create a free online database. # + +Now we are going to create the actual database you are going to be using. + +* Choose a Cloud Provider from the available list. + +* Select the Sandbox plan type, which is the only one with no cost, and press Continue. + +* Select a region for your Sandbox, from the available list, and press Continue. + +* Input a name for your database. This name will be used in the URI for your database. After that, press Continue. + +A summary of all your choices should appear, allowing you to change any information provided in the previous steps. Press **Submit Order** to confirm the information. + +# Create a new admin user on the database # + +After you confirmed your configuration, a new sandbox should have been created in the MongoDB Deployments section. We are now going to create an administrator, so you can use the database in your application. + +* Click the newly-created database. + +* Click the Users section. + +* Click the Add database user button. + +* Input an username and password for your administrator. Do not mark it as read-only or you will not be able to add any information to the database with this user. + +# Get the mLab URI # + +Almost done! We have created our new database and created an user to access it, so we just need to find a way to use it in our applications. + +* In your database page, you should see some instructions about connecting using the standard MongoDB URI. + +* The line should look like this mongodb://dbuser:dbpassword@ds0.mlab.com:/. + +* Copy this URI and substitute dbuser and dbpassword with the information for the user you previously created in the database. + +* That's it! This is the URI you will add to your application to connect to your database. Keep this URI safe somewhere, so you can use it later! + +* Feel free to create separate databases for different applications, if they don't have an use for the same data. You just need to create the sandbox, user and obtain the new URI. diff --git a/06-information-security-and-quality-assurance/advanced-express-tools.json b/06-information-security-and-quality-assurance/advanced-node-and-express.json similarity index 100% rename from 06-information-security-and-quality-assurance/advanced-express-tools.json rename to 06-information-security-and-quality-assurance/advanced-node-and-express.json diff --git a/06-information-security-and-quality-assurance/advanced-node-and-express.md b/06-information-security-and-quality-assurance/advanced-node-and-express.md new file mode 100644 index 0000000..f1eb377 --- /dev/null +++ b/06-information-security-and-quality-assurance/advanced-node-and-express.md @@ -0,0 +1,5 @@ +# Introduction to Advanced Node and Express Challenges # + +Authentication is the process or action of verifying the identity of a user or process. Up to this point you have not been able to create an app utilizing this key concept. + +The most common and easiest to use authentication middleware for Node.js is Passport. It is easy to learn, light-weight, and extremely flexible allowing for many strategies, which we will talk about in later challenges. In addition to authentication we will also look at template engines which allow for use of Pug and web sockets which allow for real time communication between all your clients and your server. Working on these challenges will involve you writing your code on Glitch on our starter project. After completing each challenge you can copy your public glitch url (to the homepage of your app) into the challenge screen to test it! Optionally you may choose to write your project on another platform but it must be publicaly visible for our testing. Start this project on Glitch using this link or clone this repository on GitHub! If you use Glitch, remember to save the link to your project somewhere safe. diff --git a/06-information-security-and-quality-assurance/quality-assurance-and-information-security-projects.json b/06-information-security-and-quality-assurance/information-security-and-quality-assurance-projects.json similarity index 100% rename from 06-information-security-and-quality-assurance/quality-assurance-and-information-security-projects.json rename to 06-information-security-and-quality-assurance/information-security-and-quality-assurance-projects.json diff --git a/06-information-security-and-quality-assurance/information-security-and-quality-assurance-projects.md b/06-information-security-and-quality-assurance/information-security-and-quality-assurance-projects.md new file mode 100644 index 0000000..a169cee --- /dev/null +++ b/06-information-security-and-quality-assurance/information-security-and-quality-assurance-projects.md @@ -0,0 +1,6 @@ +# Introduction to the Information Security and Quality Assurance Projects # + +This introduction is a stub + +Help us make it real on [GitHub](https://github.com/freeCodeCamp/learn/tree/master/src/introductions). + diff --git a/06-information-security-and-quality-assurance/helmetjs.json b/06-information-security-and-quality-assurance/information-security-with-helmetjs.json similarity index 82% rename from 06-information-security-and-quality-assurance/helmetjs.json rename to 06-information-security-and-quality-assurance/information-security-with-helmetjs.json index bfc897b..6eda557 100644 --- a/06-information-security-and-quality-assurance/helmetjs.json +++ b/06-information-security-and-quality-assurance/information-security-with-helmetjs.json @@ -8,12 +8,12 @@ "id": "587d8247367417b2b2512c36", "title": "Install and Require Helmet", "description": [ - "As a reminder, this project is being built upon the following starter project on Glitch, or cloned from GitHub.", - "Helmet helps you secure your Express apps by setting various HTTP headers. Install the package, then require it." + "注意,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。", + "Helmet 通过配置不同的 HTTP 头部信息来使你的 Express 应用更加安全。安装,并引入 Helmet 这个包。" ], "tests": [ { - "text": "\"helmet\" dependency should be in package.json", + "text": "package.json 文件应该有 \"helmet\" 这个依赖包", "testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'helmet'); }, xhr => { throw new Error(xhr.responseText); })" } ], @@ -26,12 +26,12 @@ "id": "587d8247367417b2b2512c37", "title": "Hide Potentially Dangerous Information Using helmet.hidePoweredBy()", "description": [ - "As a reminder, this project is being built upon the following starter project on Glitch, or cloned from GitHub.", - "Hackers can exploit known vulnerabilities in Express/Node if they see that your site is powered by Express. X-Powered-By: Express is sent in every request coming from Express by default. The helmet.hidePoweredBy() middleware will remove the X-Powered-By header. You can also explicitly set the header to something else, to throw people off. e.g. app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))" + "温馨提醒,本项目在 这个 Glitch 项目 的基础上进行开发。你也可以从 GitHub 上克隆。", + "如果黑客发现你的网站是用 Express 搭建的,那么他们就可以利用 Express 或 Node 现存的漏洞来攻击你的网站。X-Powered-By: Express 默认情况下会被添加到所有响应的头部。不过 helmet.hidePoweredBy() 中间件可以帮你移除 X-Powered-By 头。你甚至可以把头设置成其它的值。 如 app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))" ], "tests": [ { - "text": "helmet.hidePoweredBy() middleware should be mounted correctly", + "text": "helmet.hidePoweredBy() 中间件应该被正确加载", "testString": "getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hidePoweredBy'); assert.notEqual(data.headers['x-powered-by'], 'Express')}, xhr => { throw new Error(xhr.responseText); })" } ], @@ -44,17 +44,17 @@ "id": "587d8247367417b2b2512c38", "title": "Mitigate the Risk of Clickjacking with helmet.frameguard()", "description": [ - "As a reminder, this project is being built upon the following starter project on Glitch, or cloned from GitHub.", - "Your page could be put in a or