├── .DS_Store ├── README.md ├── arithmetic └── twoNumber-sum.md ├── countDown ├── .DS_Store ├── app.js ├── app.json ├── app.wxss ├── colorui │ ├── animation.wxss │ ├── components │ │ ├── cu-custom.js │ │ ├── cu-custom.json │ │ ├── cu-custom.wxml │ │ └── cu-custom.wxss │ ├── icon.wxss │ └── main.wxss ├── components │ └── circle │ │ ├── circle.js │ │ ├── circle.json │ │ ├── circle.wxml │ │ └── circle.wxss ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── main │ │ ├── main.js │ │ ├── main.json │ │ ├── main.wxml │ │ └── main.wxss ├── project.config.json ├── sitemap.json └── utils │ └── util.js ├── css-attribute ├── fixed.jpg ├── location.md ├── relative.jpg ├── select.png ├── selector.md └── selector.png ├── css └── css-questions.md ├── html └── html-questions.md ├── img ├── display-adjust.png ├── element-mask.jpg ├── element-size.png ├── sort-compare.png └── tip-box.jpg ├── javascript思维导图.md └── js ├── es6 ├── equal.jpg ├── equalJson.md └── promise.md └── javascript-questions.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hengxuZ/js-react-css-html-interview-question/5301f87459803622009c0164406a7c9cb7f9fe6c/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 写了几年代码,也赚不到啥钱。不如玩NFT。欢迎加群V:erwaNFT 2 | --- 3 | 4 | # 为什么要创建这个仓库?💪 5 | 6 | 7 | 👶小时候学习的经历告诉我,当学会了某个单一的知识点需要通过例题对它的概念以及用进行考察,以助于我能更好的掌握理解。 8 | 9 | 当一个章节学完后✍,还是通过例题对这个章节所涉及的知识点进行考察,从点到面的考察,将这些知识点贯穿起来,达到对知识点的更深入的理解。 10 | 11 | 相同地,我认为前端学习过程中,习题是至关重要的一部分,所以我收集了全网对应章节的笔试,面试题进行解答。📗 12 | 13 | 不定时更新面试题📚。为我自己加深知识点的同时,也希望能够给其他小伙伴带来便利。希望每个小伙伴都能学有所获,学以致用,然后能够取得自己心仪的offer👍 14 | 15 | ## 使用说明📑 16 | 17 | - 对相关知识点**概念**有初步了解👆 18 | - 根据题目思考解答思路✌ 19 | - 再点击进入查看题目答案👌 20 | 21 | ---- 22 | ## 目录 23 | 24 | ## 全网前端面试文章 25 |
26 | 掘金(点赞数过千的优秀文章) 27 | 28 | - [2020年前端面试复习必读文章](https://juejin.im/post/5e8b163ff265da47ee3f54a6) 29 | 30 | - [写给女朋友的中级前端面试秘籍(含详细答案,15k级别)](https://juejin.im/post/5e7af0685188255dcf4a497e) 31 | 32 | - [【前端面试分享】- 寒冬求职上篇](https://juejin.im/post/5cdb7bc26fb9a0321557044d) 33 | 34 | - [【前端面试分享】- 寒冬求职下篇](https://juejin.im/post/5cdcc009e51d453afb40d87c) 35 | 36 | - [中高级前端大厂面试秘籍,为你保驾护航金三银四,直通大厂(上)](https://juejin.im/post/5c64d15d6fb9a049d37f9c20) 37 | 38 | - [中高级前端大厂面试秘籍,寒冬中为您保驾护航,直通大厂(中篇)](https://juejin.im/post/5c92f499f265da612647b754) 39 | 40 | - [中高级前端大厂面试秘籍,寒冬中为您保驾护航,直通大厂(下篇)](https://juejin.im/post/5cc26dfef265da037b611738) 41 | 42 | - [web前端面试总结](https://juejin.im/post/5dafb263f265da5b9b80244d) 43 |
44 | 45 | ## 大厂技术分享 46 | 47 | - [腾讯前端 Web 团队IMWEB](http://imweb.io) 48 | - [腾讯 Web 前端团队 Alloy Team](http://www.alloyteam.com) 49 | - [淘宝前端团队](http://taobaofed.org) 50 | - [百度Web前端研发部](http://fex.baidu.com) 51 | - [京东凹凸实验室](https://aotu.io) 52 | - [360奇舞团](https://75team.com) 53 | - [七牛团队技术博客](http://blog.qiniu.com) 54 | - [有赞技术团队](http://tech.youzan.com) 55 | - [大搜车技术博客](https://blog.souche.com) 56 | - [美团](https://tech.meituan.com/) 57 | 58 | ## 前端在线书籍文档 59 |
60 | CSS/HTML 61 | 62 | * [学习CSS布局](http://zh.learnlayout.com/) 63 | * [通用 CSS 笔记、建议与指导](https://github.com/chadluo/CSS-Guidelines/blob/master/README.md) 64 | * [CSS参考手册](http://css.doyoe.com/) 65 | * [Emmet 文档](http://yanxyz.github.io/emmet-docs/) 66 | * [前端代码规范](http://alloyteam.github.io/CodeGuide/) (腾讯 AlloyTeam 团队) 67 | * [HTML和CSS编码规范](http://codeguide.bootcss.com/) 68 | * [Sass Guidelines 中文](http://sass-guidelin.es/zh/) 69 | * [CSS3 Tutorial 《CSS3 教程》](https://github.com/waylau/css3-tutorial) 70 | * [MDN HTML 中文文档](https://developer.mozilla.org/zh-CN/docs/Web/HTML) 71 | * [MDN CSS 中文文档](https://developer.mozilla.org/zh-CN/docs/Web/CSS) 72 |
73 |
74 | JavaScript 75 | 76 | * [现代 Javascript 教程](https://zh.javascript.info/) 77 | * [Google JavaScript 代码风格指南](http://bq69.com/blog/articles/script/868/google-javascript-style-guide.html) 78 | * [Google JSON 风格指南](https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md) 79 | * [Airbnb JavaScript 规范](https://github.com/adamlu/javascript-style-guide) 80 | * [JavaScript 标准参考教程(alpha)](http://javascript.ruanyifeng.com/) 81 | * [Javascript编程指南](http://pij.robinqu.me/) ([源码](https://github.com/RobinQu/Programing-In-Javascript)) 82 | * [javascript 的 12 个怪癖](https://github.com/justjavac/12-javascript-quirks) 83 | * [JavaScript 秘密花园](http://bonsaiden.github.io/JavaScript-Garden/zh/) 84 | * [JavaScript核心概念及实践](http://icodeit.org/jsccp/) (PDF) (此书已由人民邮电出版社出版发行,但作者依然免费提供PDF版本,希望开发者们去购买,支持作者) 85 | * [《JavaScript 模式》](https://github.com/jayli/javascript-patterns) “JavaScript patterns”中译本 86 | * [命名函数表达式探秘](http://justjavac.com/named-function-expressions-demystified.html) (注:原文由[为之漫笔](http://www.cn-cuckoo.com)翻译,原始地址无法打开,所以此处地址为我博客上的备份) 87 | * [学用 JavaScript 设计模式](http://www.oschina.net/translate/learning-javascript-design-patterns) (开源中国) 88 | * [深入理解JavaScript系列](http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html) 89 | * [ECMAScript 5.1 中文版](http://yanhaijing.com/es5) 90 | * [ECMAScript 6 入门](http://es6.ruanyifeng.com/) (作者:阮一峰) 91 | * [JavaScript Promise迷你书](http://liubin.github.io/promises-book/) 92 | * [You-Dont-Know-JS](https://github.com/getify/You-Dont-Know-JS) (深入JavaScript语言核心机制的系列图书) 93 | * [JavaScript 教程](http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000) 廖雪峰 94 | * [MDN JavaScript 中文文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript) 95 | * jQuery 96 | * [jQuery 解构](http://www.cn-cuckoo.com/deconstructed/jquery.html) 97 | * [简单易懂的JQuery魔法](http://www.nowamagic.net/librarys/books/contents/jquery) 98 | * [How to write jQuery plugin](http://i5ting.github.io/How-to-write-jQuery-plugin/build/jquery.plugin.html) 99 | * [You Don't Need jQuery](https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md) 100 | * [如何实现一个类jQuery?](https://github.com/MeCKodo/forchange) 101 | * underscore.js 102 | * [Underscore.js中文文档](http://learningcn.com/underscore/) 103 | * backbone.js 104 | * [backbone.js中文文档](http://www.css88.com/doc/backbone/) 105 | * [backbone.js入门教程](http://www.the5fire.com/backbone-js-tutorials-pdf-download.html) (PDF) 106 | * [Backbone.js入门教程第二版](https://github.com/the5fire/backbonejs-learning-note) 107 | * [Developing Backbone.js Applications(中文版)](http://feliving.github.io/developing-backbone-applications/) 108 | * AngularJS 109 | * [AngularJS最佳实践和风格指南](https://github.com/mgechev/angularjs-style-guide/blob/master/README-zh-cn.md) 110 | * [AngularJS中译本](https://github.com/peiransun/angularjs-cn) 111 | * [AngularJS入门教程](https://github.com/zensh/AngularjsTutorial_cn) 112 | * [构建自己的AngularJS](https://github.com/xufei/Make-Your-Own-AngularJS/blob/master/01.md) 113 | * [在Windows环境下用Yeoman构建AngularJS项目](http://www.waylau.com/build-angularjs-app-with-yeoman-in-windows/) 114 | * Zepto.js 115 | * [Zepto.js 中文文档](http://mweb.baidu.com/zeptoapi/) 116 | * Sea.js 117 | * [Hello Sea.js](http://island205.com/HelloSea.js/) 118 | * impress.js 119 | * [impress.js的中文教程](https://github.com/kokdemo/impress.js-tutorial-in-Chinese) 120 | * CoffeeScript 121 | * [CoffeeScript Cookbook](http://island205.com/coffeescript-cookbook.github.com/) 122 | * [The Little Book on CoffeeScript中文版](http://island205.com/tlboc/) 123 | * [CoffeeScript 编码风格指南](https://github.com/geekplux/coffeescript-style-guide) 124 | * TypeScipt 125 | * [TypeScript Handbook](https://zhongsp.gitbooks.io/typescript-handbook/content/) 126 | * ExtJS 127 | * [Ext4.1.0 中文文档](http://extjs-doc-cn.github.io/ext4api/) 128 | * Meteor 129 | * [Discover Meteor](http://zh.discovermeteor.com/) 130 | * [Meteor 中文文档](http://docs.meteorhub.org/#/basic/) 131 | * [Angular-Meteor 中文教程](http://angular.meteorhub.org/) 132 | * [Chrome扩展及应用开发](http://www.ituring.com.cn/minibook/950) 133 |
134 | 135 |
136 | React 137 | 138 | * [React 学习之道](https://github.com/the-road-to-learn-react/the-road-to-learn-react-chinese) 139 | * [React.js 小书](https://github.com/huzidaha/react-naive-book) 140 | * [React.js 中文文档](https://doc.react-china.org/) 141 | * [React webpack-cookbook](https://github.com/fakefish/react-webpack-cookbook) 142 | * [React 入门教程](http://fraserxu.me/intro-to-react/) 143 | * [React Native 中文文档(含最新Android内容)](http://wiki.jikexueyuan.com/project/react-native/) 144 | * [Learn React & Webpack by building the Hacker News front page](https://github.com/theJian/build-a-hn-front-page) 145 | 146 |
147 | 148 |
149 | NodeJS 150 | 151 | * [Node入门](http://www.nodebeginner.org/index-zh-cn.html) 152 | * [七天学会NodeJS](http://nqdeng.github.io/7-days-nodejs/) 153 | * [Nodejs Wiki Book](https://github.com/nodejs-tw/nodejs-wiki-book) (繁体中文) 154 | * [express.js 中文文档](http://expressjs.jser.us/) 155 | * [koa 中文文档](https://github.com/guo-yu/koa-guide) 156 | * [一起学koa](http://base-n.github.io/koa-generator-examples/) 157 | * [使用 Express + MongoDB 搭建多人博客](https://github.com/nswbmw/N-blog) 158 | * [Express框架](http://javascript.ruanyifeng.com/nodejs/express.html) 159 | * [Node.js 包教不包会](https://github.com/alsotang/node-lessons) 160 | * [Learn You The Node.js For Much Win! (中文版)](https://www.npmjs.com/package/learnyounode-zh-cn) 161 | * [Node debug 三法三例](http://i5ting.github.io/node-debug-tutorial/) 162 | * [nodejs中文文档](https://www.gitbook.com/book/0532/nodejs/details) 163 | * [orm2 中文文档](https://github.com/wizardforcel/orm2-doc-zh-cn) 164 | * [一起学 Node.js](https://github.com/nswbmw/N-blog) 165 | 166 |
167 | 168 | --- 169 | ## 前端学习(视频)网站推荐 170 | - [掘金](https://juejin.im/) 171 | - [思否](https://segmentfault.com/) 172 | - [慕课网](https://imooc.com) 173 | - [极客学院](http://www.jikexueyuan.com) 174 | - [前端进阶之道](https://yuchengkai.cn/docs/frontend/) 175 | - [牛客网](https://www.nowcoder.com/) 176 | 177 | ## 面试题 178 | - [JS概念类面试题汇总](https://github.com/hengxuZ/CSS-interview-question/tree/master/js/javascript-questions.md)👈 179 | - [HTML概念类面试题汇总](https://github.com/hengxuZ/CSS-interview-question/tree/master/html/html-questions.md)👈 180 | - [CSS概念类面试题汇总](https://github.com/hengxuZ/CSS-interview-question/tree/master/css/css-questions.md)👈 181 | - [前端知识思维导图](https://github.com/hengxuZ/CSS-interview-question/tree/master/javascript思维导图.md) 182 | -------------------------------------------------------------------------------- /arithmetic/twoNumber-sum.md: -------------------------------------------------------------------------------- 1 | ## 两数求和 2 | 3 | **题目描述** 4 | 5 | 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 6 | 7 | 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 8 | 9 | **举例** 10 | ``` 11 | 给定 nums = [2, 7, 11, 15], target = 9 12 | 13 | 因为 nums[0] + nums[1] = 2 + 7 = 9 14 | 所以返回 [0, 1] 15 | ``` 16 | 17 | 方法一:暴力法 18 | ``` 19 | function(nums, target) { 20 | for(let i=0;i{ 35 | map.set(v,i) //将arr的健值放入Map 36 | }) 37 | for(let i=0;i { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | // 获取系统状态栏信息 36 | wx.getSystemInfo({ 37 | success: e => { 38 | this.globalData.StatusBar = e.statusBarHeight; 39 | let custom = wx.getMenuButtonBoundingClientRect(); 40 | this.globalData.Custom = custom; 41 | this.globalData.CustomBar = custom.bottom + custom.top - e.statusBarHeight; 42 | } 43 | }) 44 | }, 45 | globalData: { 46 | userInfo: null 47 | } 48 | }) -------------------------------------------------------------------------------- /countDown/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/main/main", 4 | "pages/index/index", 5 | "components/circle/circle" 6 | ], 7 | "window": { 8 | "backgroundTextStyle": "light", 9 | "navigationBarBackgroundColor": "#fff", 10 | "navigationBarTitleText": "ColorUI", 11 | "navigationStyle": "custom", 12 | "navigationBarTextStyle": "white" 13 | }, 14 | "usingComponents": { 15 | "cu-custom": "/colorui/components/cu-custom" 16 | }, 17 | "sitemapLocation": "sitemap.json" 18 | } -------------------------------------------------------------------------------- /countDown/app.wxss: -------------------------------------------------------------------------------- 1 | @import "colorui/main.wxss"; 2 | @import "colorui/icon.wxss"; 3 | -------------------------------------------------------------------------------- /countDown/colorui/animation.wxss: -------------------------------------------------------------------------------- 1 | /* 2 | Animation 微动画 3 | 基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28 4 | */ 5 | 6 | /* css 滤镜 控制黑白底色gif的 */ 7 | .gif-black{ 8 | mix-blend-mode: screen; 9 | } 10 | .gif-white{ 11 | mix-blend-mode: multiply; 12 | } 13 | 14 | 15 | /* Animation css */ 16 | [class*=animation-] { 17 | animation-duration: .5s; 18 | animation-timing-function: ease-out; 19 | animation-fill-mode: both 20 | } 21 | 22 | .animation-fade { 23 | animation-name: fade; 24 | animation-duration: .8s; 25 | animation-timing-function: linear 26 | } 27 | 28 | .animation-scale-up { 29 | animation-name: scale-up 30 | } 31 | 32 | .animation-scale-down { 33 | animation-name: scale-down 34 | } 35 | 36 | .animation-slide-top { 37 | animation-name: slide-top 38 | } 39 | 40 | .animation-slide-bottom { 41 | animation-name: slide-bottom 42 | } 43 | 44 | .animation-slide-left { 45 | animation-name: slide-left 46 | } 47 | 48 | .animation-slide-right { 49 | animation-name: slide-right 50 | } 51 | 52 | .animation-shake { 53 | animation-name: shake 54 | } 55 | 56 | .animation-reverse { 57 | animation-direction: reverse 58 | } 59 | 60 | @keyframes fade { 61 | 0% { 62 | opacity: 0 63 | } 64 | 65 | 100% { 66 | opacity: 1 67 | } 68 | } 69 | 70 | @keyframes scale-up { 71 | 0% { 72 | opacity: 0; 73 | transform: scale(.2) 74 | } 75 | 76 | 100% { 77 | opacity: 1; 78 | transform: scale(1) 79 | } 80 | } 81 | 82 | @keyframes scale-down { 83 | 0% { 84 | opacity: 0; 85 | transform: scale(1.8) 86 | } 87 | 88 | 100% { 89 | opacity: 1; 90 | transform: scale(1) 91 | } 92 | } 93 | 94 | @keyframes slide-top { 95 | 0% { 96 | opacity: 0; 97 | transform: translateY(-100%) 98 | } 99 | 100 | 100% { 101 | opacity: 1; 102 | transform: translateY(0) 103 | } 104 | } 105 | 106 | @keyframes slide-bottom { 107 | 0% { 108 | opacity: 0; 109 | transform: translateY(100%) 110 | } 111 | 112 | 100% { 113 | opacity: 1; 114 | transform: translateY(0) 115 | } 116 | } 117 | 118 | @keyframes shake { 119 | 120 | 0%, 121 | 100% { 122 | transform: translateX(0) 123 | } 124 | 125 | 10% { 126 | transform: translateX(-9px) 127 | } 128 | 129 | 20% { 130 | transform: translateX(8px) 131 | } 132 | 133 | 30% { 134 | transform: translateX(-7px) 135 | } 136 | 137 | 40% { 138 | transform: translateX(6px) 139 | } 140 | 141 | 50% { 142 | transform: translateX(-5px) 143 | } 144 | 145 | 60% { 146 | transform: translateX(4px) 147 | } 148 | 149 | 70% { 150 | transform: translateX(-3px) 151 | } 152 | 153 | 80% { 154 | transform: translateX(2px) 155 | } 156 | 157 | 90% { 158 | transform: translateX(-1px) 159 | } 160 | } 161 | 162 | @keyframes slide-left { 163 | 0% { 164 | opacity: 0; 165 | transform: translateX(-100%) 166 | } 167 | 168 | 100% { 169 | opacity: 1; 170 | transform: translateX(0) 171 | } 172 | } 173 | 174 | @keyframes slide-right { 175 | 0% { 176 | opacity: 0; 177 | transform: translateX(100%) 178 | } 179 | 180 | 100% { 181 | opacity: 1; 182 | transform: translateX(0) 183 | } 184 | } -------------------------------------------------------------------------------- /countDown/colorui/components/cu-custom.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | Component({ 3 | /** 4 | * 组件的一些选项 5 | */ 6 | options: { 7 | addGlobalClass: true, 8 | multipleSlots: true 9 | }, 10 | /** 11 | * 组件的对外属性 12 | */ 13 | properties: { 14 | bgColor: { 15 | type: String, 16 | default: '' 17 | }, 18 | isCustom: { 19 | type: [Boolean, String], 20 | default: false 21 | }, 22 | isBack: { 23 | type: [Boolean, String], 24 | default: false 25 | }, 26 | bgImage: { 27 | type: String, 28 | default: '' 29 | }, 30 | }, 31 | /** 32 | * 组件的初始数据 33 | */ 34 | data: { 35 | StatusBar: app.globalData.StatusBar, 36 | CustomBar: app.globalData.CustomBar, 37 | Custom: app.globalData.Custom 38 | }, 39 | /** 40 | * 组件的方法列表 41 | */ 42 | methods: { 43 | BackPage() { 44 | wx.navigateBack({ 45 | delta: 1 46 | }); 47 | }, 48 | toHome(){ 49 | wx.reLaunch({ 50 | url: '/pages/index/index', 51 | }) 52 | } 53 | } 54 | }) -------------------------------------------------------------------------------- /countDown/colorui/components/cu-custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /countDown/colorui/components/cu-custom.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /countDown/colorui/components/cu-custom.wxss: -------------------------------------------------------------------------------- 1 | /* colorui/components/cu-custom.wxss */ -------------------------------------------------------------------------------- /countDown/components/circle/circle.js: -------------------------------------------------------------------------------- 1 | /* components/circle/circle.js */ 2 | Component({ 3 | options: { 4 | multipleSlots: true // 在组件定义时的选项中启用多slot支持 5 | }, 6 | properties: { 7 | bg: { // 属性名 8 | type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型) 9 | value: 'bg' // 属性初始值(可选),如果未指定则会根据类型选择一个 10 | }, 11 | draw: { 12 | type: String, 13 | value: 'draw' 14 | }, 15 | }, 16 | 17 | data: { /* 私有数据,可用于模版渲染 */ 18 | size: 0, /* 圆环盒子大小 size >= 2*x ( x 为canvas的绘制半径)*/ 19 | step: 1, 20 | num: 100 21 | }, 22 | methods: { 23 | /* 24 | * 有关参数 25 | * id : canvas 组件的唯一标识符 canvas-id 26 | * x : canvas 绘制圆形的半径 27 | * w : canvas 绘制圆环的宽度 28 | */ 29 | drawCircleBg: function (id, x, w) { 30 | // 设置圆环外面盒子大小 宽高都等于圆环直径 31 | this.setData({ 32 | size: 2 * x // 更新属性和数据的方法与更新页面数据的方法类似 33 | }); 34 | // 使用 wx.createContext 获取绘图上下文 ctx 绘制背景圆环 35 | var ctx = wx.createCanvasContext(id, this) 36 | ctx.setLineWidth(w / 2); 37 | ctx.setStrokeStyle('#20183b'); 38 | ctx.setLineCap('round') 39 | ctx.beginPath();//开始一个新的路径 40 | //设置一个原点(x,y),半径为r的圆的路径到当前路径 此处x=y=r 41 | ctx.arc(x, x, x - w, 0, 2 * Math.PI, false); 42 | ctx.stroke();//对当前路径进行描边 43 | ctx.draw(); 44 | }, 45 | drawCircle: function (id, x, w, step) { 46 | // 使用 wx.createContext 获取绘图上下文 context 绘制彩色进度条圆环 47 | var context = wx.createCanvasContext(id, this); 48 | // 设置渐变 49 | var gradient = context.createLinearGradient(2 * x, x, 0); 50 | gradient.addColorStop("0", "#2661DD"); 51 | gradient.addColorStop("0.5", "#40ED94"); 52 | gradient.addColorStop("1.0", "#5956CC"); 53 | context.setLineWidth(w); 54 | context.setStrokeStyle(gradient); 55 | context.setLineCap('round') 56 | context.beginPath();//开始一个新的路径 57 | // step 从0到2为一周 58 | context.arc(x, x, x - w, -Math.PI / 2, step * Math.PI - Math.PI / 2, false); 59 | context.stroke();//对当前路径进行描边 60 | context.draw() 61 | }, 62 | /* 内部私有方法建议以下划线开头 , 63 | * 自定义组件触发事件时,需要使用 triggerEvent 方法,指定事件名、detail对象和事件选项 */ 64 | _runEvent() { 65 | //触发自定义组件事件 66 | this.triggerEvent("runEvent") 67 | } 68 | }, 69 | 70 | // 生命周期函数,可以为函数,或一个在methods段中定义的方法名 71 | onReady: function () { 72 | } 73 | }) -------------------------------------------------------------------------------- /countDown/components/circle/circle.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {}, 3 | "component": true 4 | } -------------------------------------------------------------------------------- /countDown/components/circle/circle.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /countDown/components/circle/circle.wxss: -------------------------------------------------------------------------------- 1 | /* components/circle/circle.wxss */ 2 | .circle_box,.circle_draw{ position: relative; } 3 | .circle_bg{position: absolute;} -------------------------------------------------------------------------------- /countDown/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | StatusBar: app.globalData.StatusBar, 8 | CustomBar: app.globalData.CustomBar, 9 | txt: "正在匹配中...", 10 | count: 0,//计数器,初始值为0 11 | maxCount: 100, // 绘制一个圆环所需的步骤 12 | countTimer: null,//定时器,初始值为null 13 | }, 14 | countInterval: function () { 15 | // 设置倒计时 定时器 假设每隔100毫秒 count递增+1,当 count递增到两倍maxCount的时候刚好是一个圆环( step 从0到2为一周),然后改变txt值并且清除定时器 16 | this.countTimer = setInterval(() => { 17 | if (this.data.count <= 2 * this.data.maxCount) { 18 | // 绘制彩色圆环进度条 19 | this.circle1.drawCircle('circle_draw1', 100, 8, this.data.count / this.data.maxCount) 20 | this.data.count++; 21 | } else { 22 | this.setData({ 23 | txt: "匹配成功" 24 | }); 25 | clearInterval(this.countTimer); 26 | } 27 | }, 100) 28 | }, 29 | onReady: function () { 30 | // 获得circle组件 31 | this.circle1 = this.selectComponent("#circle1"); 32 | // 绘制背景圆环 33 | this.circle1.drawCircleBg('circle_bg1', 100, 8) 34 | // 绘制彩色圆环 35 | // this.circle.drawCircle('circle_draw1', 100, 8, 2); 36 | this.countInterval() 37 | }, 38 | 39 | //事件处理函数 40 | bindViewTap: function() { 41 | wx.navigateTo({ 42 | url: '../logs/logs' 43 | }) 44 | }, 45 | onLoad: function () { 46 | if (app.globalData.userInfo) { 47 | this.setData({ 48 | userInfo: app.globalData.userInfo, 49 | hasUserInfo: true 50 | }) 51 | } else if (this.data.canIUse){ 52 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 53 | // 所以此处加入 callback 以防止这种情况 54 | app.userInfoReadyCallback = res => { 55 | this.setData({ 56 | userInfo: res.userInfo, 57 | hasUserInfo: true 58 | }) 59 | } 60 | } else { 61 | // 在没有 open-type=getUserInfo 版本的兼容处理 62 | wx.getUserInfo({ 63 | success: res => { 64 | app.globalData.userInfo = res.userInfo 65 | this.setData({ 66 | userInfo: res.userInfo, 67 | hasUserInfo: true 68 | }) 69 | } 70 | }) 71 | } 72 | }, 73 | getUserInfo: function(e) { 74 | console.log(e) 75 | app.globalData.userInfo = e.detail.userInfo 76 | this.setData({ 77 | userInfo: e.detail.userInfo, 78 | hasUserInfo: true 79 | }) 80 | } 81 | }) 82 | -------------------------------------------------------------------------------- /countDown/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "circle": "/components/circle/circle" 4 | } 5 | } -------------------------------------------------------------------------------- /countDown/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | ColorUI 空白模板 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | {{txt}} 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | {{time}} s 26 | 27 | 28 | -------------------------------------------------------------------------------- /countDown/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | /*圆环进度条文字*/ 3 | .circle_info{ 4 | position: absolute; 5 | width: 100%; 6 | left: 50%; 7 | top: 50%; 8 | transform: translate(-50%,-50%); 9 | display: flex; 10 | align-items: center; 11 | justify-content: center 12 | } 13 | .circle_dot{ 14 | width:16rpx; 15 | height: 16rpx; 16 | border-radius: 50%; 17 | background-color: #fb9126; 18 | } 19 | .circle_txt{ 20 | padding-left: 10rpx; 21 | color: #fff; 22 | font-size: 36rpx; 23 | letter-spacing: 2rpx; 24 | } 25 | 26 | .circle_text{ 27 | position: absolute; 28 | left: 50%; 29 | top: 50%; 30 | transform: translate(-50%,-50%); 31 | } 32 | .circle_time{ 33 | color: #fff; 34 | font-size: 32rpx; 35 | padding-left: 16rpx; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /countDown/pages/main/main.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | Page({ 5 | data: { 6 | StatusBar: app.globalData.StatusBar, 7 | CustomBar: app.globalData.CustomBar, 8 | num: 100, 9 | step: null, 10 | time: null, 11 | stepTimer: null, 12 | }, 13 | stepInterval: function () { 14 | // 设置倒计时 定时器 15 | var n = this.data.num / 2 16 | this.stepTimer = setInterval(() => { 17 | if (this.data.num >= 0) { 18 | this.data.step = this.data.num / n; 19 | // 绘制彩色圆环进度条 20 | this.circle.drawCircle('circle_draw', 40, 4, this.data.step) 21 | if ((/(^[1-9]\d*$)/.test(this.data.num / 10))) { 22 | // 当时间为整数秒的时候 改变时间 23 | this.setData({ 24 | time: this.data.num / 10 25 | }); 26 | } 27 | this.data.num--; 28 | } else { 29 | this.setData({ 30 | time: 0 31 | }); 32 | clearInterval(this.stepTimer); 33 | } 34 | }, 100) 35 | }, 36 | changeTime: function () { 37 | // 先清除定时器 38 | clearInterval(this.stepTimer); 39 | // 计数器 还原到100 40 | this.setData({ 41 | num: 100 42 | }); 43 | // 重新开启倒计时 44 | this.stepInterval() 45 | // 触发自定义组件事件 46 | this._runEvent() 47 | }, 48 | onLoad: function () { 49 | }, 50 | onReady: function () { 51 | /*倒计时*/ 52 | // 获得circle组件 53 | this.circle = this.selectComponent("#circle"); 54 | // 绘制背景圆环 55 | this.circle.drawCircleBg('circle_bg', 40, 4) 56 | // 绘制彩色圆环 57 | this.stepInterval() 58 | }, 59 | 60 | _runEvent() { 61 | console.log(1111) 62 | }, 63 | }) 64 | -------------------------------------------------------------------------------- /countDown/pages/main/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "circle": "/components/circle/circle" 4 | } 5 | } -------------------------------------------------------------------------------- /countDown/pages/main/main.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ColorUI 空白模板 4 | 5 | 6 | 7 | 11 | 12 | {{time}} s 13 | 14 | 15 | -------------------------------------------------------------------------------- /countDown/pages/main/main.wxss: -------------------------------------------------------------------------------- 1 | /* pages/main/main.wxss */ 2 | .circle_txt{ 3 | padding-left: 10rpx; 4 | color: #fff; 5 | font-size: 36rpx; 6 | letter-spacing: 2rpx; 7 | } 8 | 9 | .circle_text{ 10 | position: absolute; 11 | left: 50%; 12 | top: 50%; 13 | transform: translate(-50%,-50%); 14 | } 15 | .circle_time{ 16 | color: #000; 17 | font-size: 32rpx; 18 | padding-left: 16rpx; 19 | } -------------------------------------------------------------------------------- /countDown/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "autoAudits": false 13 | }, 14 | "compileType": "miniprogram", 15 | "libVersion": "2.4.2", 16 | "appid": "wx78921672d8c14cb8", 17 | "projectname": "countDown", 18 | "debugOptions": { 19 | "hidedInDevtools": [] 20 | }, 21 | "isGameTourist": false, 22 | "simulatorType": "wechat", 23 | "simulatorPluginLibVersion": {}, 24 | "condition": { 25 | "search": { 26 | "current": -1, 27 | "list": [] 28 | }, 29 | "conversation": { 30 | "current": -1, 31 | "list": [] 32 | }, 33 | "game": { 34 | "currentL": -1, 35 | "list": [] 36 | }, 37 | "miniprogram": { 38 | "current": -1, 39 | "list": [] 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /countDown/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /countDown/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /css-attribute/fixed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hengxuZ/js-react-css-html-interview-question/5301f87459803622009c0164406a7c9cb7f9fe6c/css-attribute/fixed.jpg -------------------------------------------------------------------------------- /css-attribute/location.md: -------------------------------------------------------------------------------- 1 | ### css定位有哪些,区别是什么? 2 | 3 | 属性值 | 描述 | 脱离文档流?| 是否可以使用top,left| 4 | --|--|--|-- 5 | static |默认值,默认位置没有定位|否|否| 6 | relative |相对于自身第一个位置定位|否|是| 7 | absolute |相对于离元素最近的设置了**绝对或相对定位**的父元素|是|是| 8 | fixed |对于浏览器窗口是固定位置|是|是| 9 | z-index|元素的堆叠顺序|否|否| 10 | sticky|相对定位和固定定位的混合(适用于吸顶效果) |是|是 11 | inherit|从父元素继承 position 属性的值。| 12 | 13 | 14 | --- 15 | 16 | ### 如何判断是否脱离文档流? 17 | - relative布局时,设置了left.但下方盒子并没有上移,说明上方盒子占据着位置。他们是同一个文档流。对比absolute布局 18 | 19 | ![](./relative.jpg "relative布局") 20 | 21 | - z-index布局时,下方盒子并没有上移,说明上方盒子占据着位置。他们是同一个文档流,对比fixed布局 22 | 23 | ![](./fixed.jpg "fixed布局") 24 | -------------------------------------------------------------------------------- /css-attribute/relative.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hengxuZ/js-react-css-html-interview-question/5301f87459803622009c0164406a7c9cb7f9fe6c/css-attribute/relative.jpg -------------------------------------------------------------------------------- /css-attribute/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hengxuZ/js-react-css-html-interview-question/5301f87459803622009c0164406a7c9cb7f9fe6c/css-attribute/select.png -------------------------------------------------------------------------------- /css-attribute/selector.md: -------------------------------------------------------------------------------- 1 | ### css选择器有哪些以及它们的优先级? 2 | 3 | 选择器 | 名称 |描述 4 | --|--|-- 5 | #id|id选择器| 6 | .class|类选择器| 7 | a|元素选择器| 指的是元素标签如h1,div 8 | div,p|分组选择器|多个选择器同时满足对应规则 9 | a[href]|属性选择器|指的是**标签元素**并且**属性**相同的节点 10 | div p|后代选择器| 见下 11 | div>p|子元素选择器| 见下 12 | div+p|相邻选择器|相同父元素,并且是相邻元素 13 | a:hover|伪类选择器| 14 | *|通配符选择器|选择所有的元素标签 15 | 16 | --- 17 | ### 选择器优先级 18 | 19 | 内联样式 > ID 选择器 > 类选择器 = 属性选择器 = 伪类选择器 > 标签选择器 = 伪元素选择器 20 | 21 | --- 22 | 23 | ### 后代选择器与子元素选择器区别 24 | 25 | 26 | ``` 27 |
28 | 我是span标签 29 |

段落

30 |

31 | 我是P元素下的span标签 32 |

33 |
34 | ``` 35 | 后代选择器 36 | ``` 37 | div span { 38 | color:red; 39 | } 40 | ``` 41 | ### 结果如图: 42 | ![](./selector.png "relative布局") 43 | 44 | 子元素选择器 45 | ``` 46 | div>span { 47 | color:red; 48 | } 49 | ``` 50 | 结果如图: 51 | 52 | ![](./select.png "relative布局") 53 | 54 | **结论:** 子元素选择器只选择元素标签的子元素不会选择孙子元素(嵌套中的span),而后代选择器会选择元素标签内的所有span元素 -------------------------------------------------------------------------------- /css-attribute/selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hengxuZ/js-react-css-html-interview-question/5301f87459803622009c0164406a7c9cb7f9fe6c/css-attribute/selector.png -------------------------------------------------------------------------------- /css/css-questions.md: -------------------------------------------------------------------------------- 1 | # CSS 问题 2 | 3 | 欢迎提出 PR 进行建议和指正! 4 | 5 | * [CSS 选择器的优先级是如何计算的?](#css-选择器的优先级是如何计算的) 6 | * [重置(resetting)CSS 和 标准化(normalizing)CSS 的区别是什么?你会选择哪种方式,为什么?](#重置resettingcss-和-标准化normalizingcss-的区别是什么你会选择哪种方式为什么) 7 | * [请阐述`Float`定位的工作原理。](#请阐述float定位的工作原理) 8 | * [请阐述`z-index`属性,并说明如何形成层叠上下文(stacking context)。](#请阐述z-index属性并说明如何形成层叠上下文stacking-context) 9 | * [请阐述块格式化上下文(Block Formatting Context)及其工作原理。](#请阐述块格式化上下文block-formatting-context及其工作原理) 10 | * [有哪些清除浮动的技术,都适用哪些情况?](#有哪些清除浮动的技术都适用哪些情况) 11 | * [请解释什么是雪碧图(css sprites),以及如何实现?](#请解释什么是雪碧图css-sprites以及如何实现) 12 | * [如何解决不同浏览器的样式兼容性问题?](#如何解决不同浏览器的样式兼容性问题) 13 | * [如何为功能受限的浏览器提供页面? 使用什么样的技术和流程?](#如何为功能受限的浏览器提供页面-使用什么样的技术和流程) 14 | * [有什么不同的方式可以隐藏内容(使其仅适用于屏幕阅读器)?](#有什么不同的方式可以隐藏内容使其仅适用于屏幕阅读器) 15 | * [你使用过栅格系统吗?偏爱哪一个?](#你使用过栅格系统吗偏爱哪一个) 16 | * [你是否使用过媒体查询或移动优先的布局?](#你是否使用过媒体查询或移动优先的布局) 17 | * [你熟悉制作 SVG 吗?](#你熟悉制作-svg-吗) 18 | * [除了`screen`,你还能说出一个 @media 属性的例子吗?](#除了screen你还能说出一个-media-属性的例子吗) 19 | * [编写高效的 CSS 应该注意什么?](#编写高效的-css-应该注意什么) 20 | * [使用 CSS 预处理的优缺点分别是什么?](#使用-css-预处理的优缺点分别是什么) 21 | * [对于你使用过的 CSS 预处理,说说喜欢和不喜欢的地方?](#对于你使用过的-css-预处理说说喜欢和不喜欢的地方) 22 | * [如何实现一个使用非标准字体的网页设计?](#如何实现一个使用非标准字体的网页设计) 23 | * [解释浏览器如何确定哪些元素与 CSS 选择器匹配。](#解释浏览器如何确定哪些元素与-css-选择器匹配) 24 | * [描述伪元素及其用途。](#描述伪元素及其用途) 25 | * [说说你对盒模型的理解,以及如何告知浏览器使用不同的盒模型渲染布局。](#说说你对盒模型的理解以及如何告知浏览器使用不同的盒模型渲染布局) 26 | * [`* { box-sizing: border-box; }`会产生怎样的效果?](#--box-sizing-border-box-会产生怎样的效果) 27 | * [`display`的属性值都有哪些?](#display的属性值都有哪些) 28 | * [`inline`和`inline-block`有什么区别?](#inline和inline-block有什么区别) 29 | * [`relative`、`fixed`、`absolute`和`static`四种定位有什么区别?](#relativefixedabsolute和static四种定位有什么区别) 30 | * [你使用过哪些现有的 CSS 框架?你是如何改进它们的?](#你使用过哪些现有的-css-框架你是如何改进它们的) 31 | * [你了解 CSS Flexbox 和 Grid 吗?](#你了解-css-flexbox-和-grid-吗) 32 | * [请解释在编写网站时,响应式与移动优先的区别。](#请解释在编写网站时响应式与移动优先的区别) 33 | * [响应式设计与自适应设计有何不同?](#响应式设计与自适应设计有何不同) 34 | * [你有没有使用过视网膜分辨率的图形?当中使用什么技术?](#你有没有使用过视网膜分辨率的图形当中使用什么技术) 35 | * [什么情况下,用`translate()`而不用绝对定位?什么时候,情况相反。](#什么情况下用translate而不用绝对定位什么时候情况相反) 36 | - [CSS选择器有哪些](#css选择器有哪些) 37 | - [css sprite是什么,有什么优缺点](#css-sprite是什么有什么优缺点) 38 | - [`display: none;`与`visibility: hidden;`的区别](#display-none与visibility-hidden的区别) 39 | - [css hack原理及常用hack](#css-hack原理及常用hack) 40 | - [specified value,computed value,used value计算方法](#specified-valuecomputed-valueused-value计算方法) 41 | - [`link`与`@import`的区别](#link与@import的区别) 42 | - [``display: block;``和``display: inline;``的区别](#display-block和display-inline的区别) 43 | - [PNG,GIF,JPG的区别及如何选](#pnggifjpg的区别及如何选) 44 | - [CSS有哪些继承属性](#css有哪些继承属性) 45 | - [IE6浏览器有哪些常见的bug,缺陷或者与标准不一致的地方,如何解决](#ie6浏览器有哪些常见的bug缺陷或者与标准不一致的地方如何解决) 46 | - [容器包含若干浮动元素时如何清理(包含)浮动](#容器包含若干浮动元素时如何清理包含浮动) 47 | - [什么是FOUC?如何避免](#什么是fouc如何避免) 48 | - [如何创建块级格式化上下文(block formatting context),BFC有什么用](#如何创建块级格式化上下文block-formatting-contextbfc有什么用) 49 | - [display,float,position的关系](#displayfloatposition的关系) 50 | - [外边距折叠(collapsing margins)](#外边距折叠collapsing-margins) 51 | - [如何确定一个元素的包含块(containing block)](#如何确定一个元素的包含块containing-block) 52 | - [stacking context,布局规则](#stacking-context布局规则) 53 | - [如何水平居中一个元素](#如何水平居中一个元素) 54 | - [如何竖直居中一个元素](#如何竖直居中一个元素) 55 | ### CSS 选择器的优先级是如何计算的? 56 | 57 | 浏览器通过优先级规则,判断元素展示哪些样式。优先级通过 4 个维度指标确定,我们假定以`a、b、c、d`命名,分别代表以下含义: 58 | 59 | 1. `a`表示是否使用内联样式(inline style)。如果使用,`a`为 1,否则为 0。 60 | 2. `b`表示 ID 选择器的数量。 61 | 3. `c`表示类选择器、属性选择器和伪类选择器数量之和。 62 | 4. `d`表示标签(类型)选择器和伪元素选择器之和。 63 | 64 | 优先级的结果并非通过以上四个值生成一个得分,而是每个值分开比较。`a、b、c、d`权重从左到右,依次减小。判断优先级时,从左到右,一一比较,直到比较出最大值,即可停止。所以,如果`b`的值不同,那么`c`和`d`不管多大,都不会对结果产生影响。比如`0,1,0,0`的优先级高于`0,0,10,10`。 65 | 66 | 当出现优先级相等的情况时,最晚出现的样式规则会被采纳。如果你在样式表里写了相同的规则(无论是在该文件内部还是其它样式文件中),那么最后出现的(在文件底部的)样式优先级更高,因此会被采纳。 67 | 68 | 在写样式时,我会使用较低的优先级,这样这些样式可以轻易地覆盖掉。尤其对写 UI 组件的时候更为重要,这样使用者就不需要通过非常复杂的优先级规则或使用`!important`的方式,去覆盖组件的样式了。 69 | 70 | ###### 参考 71 | 72 | * https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/ 73 | * https://www.sitepoint.com/web-foundations/specificity/ 74 | 75 | [[↑] 回到顶部](#css-问题) 76 | 77 | ### 重置(resetting)CSS 和 标准化(normalizing)CSS 的区别是什么?你会选择哪种方式,为什么? 78 | 79 | * **重置(Resetting)**: 重置意味着除去所有的浏览器默认样式。对于页面所有的元素,像`margin`、`padding`、`font-size`这些样式全部置成一样。你将必须重新定义各种元素的样式。 80 | * **标准化(Normalizing)**: 标准化没有去掉所有的默认样式,而是保留了有用的一部分,同时还纠正了一些常见错误。 81 | 82 | 当需要实现非常个性化的网页设计时,我会选择重置的方式,因为我要写很多自定义的样式以满足设计需求,这时候就不再需要标准化的默认样式了。 83 | 84 | ###### 参考 85 | 86 | * https://stackoverflow.com/questions/6887336/what-is-the-difference-between-normalize-css-and-reset-css 87 | 88 | [[↑] 回到顶部](#css-问题) 89 | 90 | ### 请阐述`Float`定位的工作原理。 91 | 92 | 浮动(float)是 CSS 定位属性。浮动元素从网页的正常流动中移出,但是保持了部分的流动性,会影响其他元素的定位(比如文字会围绕着浮动元素)。这一点与绝对定位不同,绝对定位的元素完全从文档流中脱离。 93 | 94 | CSS 的`clear`属性通过使用`left`、`right`、`both`,让该元素向下移动(清除浮动)到浮动元素下面。 95 | 96 | 如果父元素只包含浮动元素,那么该父元素的高度将塌缩为 0。我们可以通过清除(clear)从浮动元素后到父元素关闭前之间的浮动来修复这个问题。 97 | 98 | 有一种 hack 的方法,是自定义一个`.clearfix`类,利用伪元素选择器`::after`清除浮动。[另外还有一些方法](https://css-tricks.com/all-about-floats/#article-header-id-4),比如添加空的`
`和设置浮动元素父元素的`overflow`属性。与这些方法不同的是,`clearfix`方法,只需要给父元素添加一个类,定义如下: 99 | 100 | ```css 101 | .clearfix::after { 102 | content: ''; 103 | display: block; 104 | clear: both; 105 | } 106 | ``` 107 | 108 | 值得一提的是,把父元素属性设置为`overflow: auto`或`overflow: hidden`,会使其内部的子元素形成块格式化上下文(Block Formatting Context),并且父元素会扩张自己,使其能够包围它的子元素。 109 | 110 | ###### 参考 111 | 112 | * https://css-tricks.com/all-about-floats/ 113 | 114 | [[↑] 回到顶部](#css-问题) 115 | 116 | ### 请阐述`z-index`属性,并说明如何形成层叠上下文(stacking context)。 117 | 118 | CSS 中的`z-index`属性控制重叠元素的垂直叠加顺序。`z-index`只能影响`position`值不是`static`的元素。 119 | 120 | 没有定义`z-index`的值时,元素按照它们出现在 DOM 中的顺序堆叠(层级越低,出现位置越靠上)。非静态定位的元素(及其子元素)将始终覆盖静态定位(static)的元素,而不管 HTML 层次结构如何。 121 | 122 | 层叠上下文是包含一组图层的元素。 在一组层叠上下文中,其子元素的`z-index`值是相对于该父元素而不是 document root 设置的。每个层叠上下文完全独立于它的兄弟元素。如果元素 B 位于元素 A 之上,则即使元素 A 的子元素 C 具有比元素 B 更高的`z-index`值,元素 C 也永远不会在元素 B 之上. 123 | 124 | 每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会在父层叠上下文中按顺序进行层叠。少数 CSS 属性会触发一个新的层叠上下文,例如`opacity`小于 1,`filter`不是`none`,`transform`不是`none`。 125 | 126 | ###### 参考 127 | 128 | * https://css-tricks.com/almanac/properties/z/z-index/ 129 | * https://philipwalton.com/articles/what-no-one-told-you-about-z-index/ 130 | * https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context 131 | 132 | [[↑] 回到顶部](#css-问题) 133 | 134 | ### 请阐述块格式化上下文(Block Formatting Context)及其工作原理。 135 | 136 | 块格式上下文(BFC)是 Web 页面的可视化 CSS 渲染的部分,是块级盒布局发生的区域,也是浮动元素与其他元素交互的区域。 137 | 138 | 一个 HTML 盒(Box)满足以下任意一条,会创建块格式化上下文: 139 | 140 | * `float`的值不是`none`. 141 | * `position`的值不是`static`或`relative`. 142 | * `display`的值是`table-cell`、`table-caption`、`inline-block`、`flex`、或`inline-flex`。 143 | * `overflow`的值不是`visible`。 144 | 145 | 在 BFC 中,每个盒的左外边缘都与其包含的块的左边缘相接。 146 | 147 | 两个相邻的块级盒在垂直方向上的边距会发生合并(collapse)。更多内容请参考[边距合并(margin collapsing)](https://www.sitepoint.com/web-foundations/collapsing-margins/)。 148 | 149 | ###### 参考 150 | 151 | * https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context 152 | * https://www.sitepoint.com/understanding-block-formatting-contexts-in-css/ 153 | 154 | [[↑] 回到顶部](#css-问题) 155 | 156 | ### 有哪些清除浮动的技术,都适用哪些情况? 157 | 158 | * 空`div`方法:`
`。 159 | * Clearfix 方法:上文使用`.clearfix`类已经提到。 160 | * `overflow: auto`或`overflow: hidden`方法:上文已经提到。 161 | 162 | 在大型项目中,我会使用 Clearfix 方法,在需要的地方使用`.clearfix`。设置`overflow: hidden`的方法可能使其子元素显示不完整,当子元素的高度大于父元素时。 163 | 164 | [[↑] 回到顶部](#css-问题) 165 | 166 | ### 请解释什么是雪碧图(css sprites),以及如何实现? 167 | 168 | 雪碧图是把多张图片整合到一张上的图片。它被运用在众多使用了很多小图标的网站上(Gmail 在使用)。实现方法: 169 | 170 | 1. 使用生成器将多张图片打包成一张雪碧图,并为其生成合适的 CSS。 171 | 1. 每张图片都有相应的 CSS 类,该类定义了`background-image`、`background-position`和`background-size`属性。 172 | 1. 使用图片时,将相应的类添加到你的元素中。 173 | 174 | 好处: 175 | 176 | * 减少加载多张图片的 HTTP 请求数(一张雪碧图只需要一个请求)。但是对于 HTTP2 而言,加载多张图片不再是问题。 177 | * 提前加载资源,防止在需要时才在开始下载引发的问题,比如只出现在`:hover`伪类中的图片,不会出现闪烁。 178 | 179 | ###### 参考 180 | 181 | * https://css-tricks.com/css-sprites/ 182 | 183 | [[↑] 回到顶部](#css-问题) 184 | 185 | ### 如何解决不同浏览器的样式兼容性问题? 186 | 187 | * 在确定问题原因和有问题的浏览器后,使用单独的样式表,仅供出现问题的浏览器加载。这种方法需要使用服务器端渲染。 188 | * 使用已经处理好此类问题的库,比如 Bootstrap。 189 | * 使用 `autoprefixer` 自动生成 CSS 属性前缀。 190 | * 使用 Reset CSS 或 Normalize.css。 191 | 192 | [[↑] 回到顶部](#css-问题) 193 | 194 | ### 如何为功能受限的浏览器提供页面? 使用什么样的技术和流程? 195 | 196 | * 优雅的降级:为现代浏览器构建应用,同时确保它在旧版浏览器中正常运行。 197 | * 渐进式增强:构建基于用户体验的应用,但在浏览器支持时添加新增功能。 198 | * 利用 [caniuse.com](https://caniuse.com/) 检查特性支持。 199 | * 使用 `autoprefixer` 自动生成 CSS 属性前缀。 200 | * 使用 [Modernizr](https://modernizr.com/)进行特性检测。 201 | 202 | [[↑] 回到顶部](#css-问题) 203 | 204 | ### 有什么不同的方式可以隐藏内容(使其仅适用于屏幕阅读器)? 205 | 206 | 这些方法与可访问性(a11y)有关。 207 | 208 | * `visibility: hidden`:元素仍然在页面流中,并占用空间。 209 | * `width: 0; height: 0`:使元素不占用屏幕上的任何空间,导致不显示它。 210 | * `position: absolute; left: -99999px`: 将它置于屏幕之外。 211 | * `text-indent: -9999px`:这只适用于`block`元素中的文本。 212 | * Metadata: 例如通过使用 Schema.org,RDF 和 JSON-LD。 213 | * WAI-ARIA:如何增加网页可访问性的 W3C 技术规范。 214 | 215 | 即使 WAI-ARIA 是理想的解决方案,我也会采用绝对定位方法,因为它具有最少的注意事项,适用于大多数元素,而且使用起来非常简单。 216 | 217 | ###### 参考 218 | 219 | * https://www.w3.org/TR/wai-aria-1.1/ 220 | * https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA 221 | * http://a11yproject.com/ 222 | 223 | [[↑] 回到顶部](#css-问题) 224 | 225 | ### 你使用过栅格系统吗?偏爱哪一个? 226 | 227 | 我使用 `float`-based 栅格系统,因为它相比 flex、grid 系统,拥有更多浏览器的支持。它已经在 Bootstrap 中使用多年,并且已经被证明是可行的。 228 | 229 | [[↑] 回到顶部](#css-问题) 230 | 231 | ### 你是否使用过媒体查询或移动优先的布局? 232 | 233 | 是的,一个例子就是根据窗口的尺寸改变导航的样式。 234 | 235 | [[↑] 回到顶部](#css-问题) 236 | 237 | ### 你熟悉制作 SVG 吗? 238 | 239 | 是的,你可以使用内联CSS、嵌入式CSS部分或外部CSS文件对形状进行着色(包括指定对象上的属性)。在网上大部分SVG使用的是内联CSS,不过每个类型都有优点和缺点。 240 | 241 | 通过设置`fill`和`stroke`属性,可以完成基本着色操作。`fill`可以设置内部的颜色,`stroke`可以设置周围绘制的线条的颜色。你可以使用与`HTML`中使用的CSS颜色命名方案相同的CSS颜色命名方案:颜色名称(即`red`)、RGB值(即`rgb(255,0,0)`)、十六进制值、RGBA值等等。 242 | 243 | ```html 244 | 246 | ``` 247 | 248 | ###### 参考 249 | 250 | * https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Fills_and_Strokes 251 | 252 | 253 | [[↑] 回到顶部](#css-问题) 254 | 255 | ### 除了`screen`,你还能说出一个 @media 属性的例子吗? 256 | 257 | TODO 258 | 259 | [[↑] 回到顶部](#css-问题) 260 | 261 | ### 编写高效的 CSS 应该注意什么? 262 | 263 | 首先,浏览器从最右边的选择器,即关键选择器(key selector),向左依次匹配。根据关键选择器,浏览器从 DOM 中筛选出元素,然后向上遍历被选元素的父元素,判断是否匹配。选择器匹配语句链越短,浏览器的匹配速度越快。避免使用标签和通用选择器作为关键选择器,因为它们会匹配大量的元素,浏览器必须要进行大量的工作,去判断这些元素的父元素们是否匹配。 264 | 265 | [BEM (Block Element Modifier)](https://bem.info/) methodology recommends that everything has a single class, and, where you need hierarchy, that gets baked into the name of the class as well, this naturally makes the selector efficient and easy to override. 266 | [BEM (Block Element Modifier)](https://bem.info/)原则上建议为独立的 CSS 类命名,并且在需要层级关系时,将关系也体现在命名中,这自然会使选择器高效且易于覆盖。 267 | 268 | 搞清楚哪些 CSS 属性会触发重新布局(reflow)、重绘(repaint)和合成(compositing)。在写样式时,避免触发重新布局的可能。 269 | 270 | ###### 参考 271 | 272 | * https://developers.google.com/web/fundamentals/performance/rendering/ 273 | * https://csstriggers.com/ 274 | 275 | [[↑] 回到顶部](#css-问题) 276 | 277 | ### 使用 CSS 预处理的优缺点分别是什么? 278 | 279 | 优点: 280 | 281 | * 提高 CSS 可维护性。 282 | * 易于编写嵌套选择器。 283 | * 引入变量,增添主题功能。可以在不同的项目中共享主题文件。 284 | * 通过混合(Mixins)生成重复的 CSS。 285 | * Splitting your code into multiple files. CSS files can be split up too but doing so will require a HTTP request to download each CSS file. 286 | * 将代码分割成多个文件。不进行预处理的 CSS,虽然也可以分割成多个文件,但需要建立多个 HTTP 请求加载这些文件。 287 | 288 | 缺点: 289 | 290 | * 需要预处理工具。 291 | * 重新编译的时间可能会很慢。 292 | 293 | [[↑] 回到顶部](#css-问题) 294 | 295 | ### 对于你使用过的 CSS 预处理,说说喜欢和不喜欢的地方? 296 | 297 | 喜欢: 298 | 299 | * 绝大部分优点上题以及提过。 300 | * Less 用 JavaScript 实现,与 NodeJS 高度结合。 301 | 302 | **Dislikes:** 303 | 304 | * 我通过`node-sass`使用 Sass,它用 C ++ 编写的 LibSass 绑定。在 Node 版本切换时,我必须经常重新编译。 305 | * Less 中,变量名称以`@`作为前缀,容易与 CSS 关键字混淆,如`@media`、`@import`和`@font-face`。 306 | 307 | [[↑] 回到顶部](#css-问题) 308 | 309 | ### 如何实现一个使用非标准字体的网页设计? 310 | 311 | 使用`@font-face`并为不同的`font-weight`定义`font-family`。 312 | 313 | [[↑] 回到顶部](#css-问题) 314 | 315 | ### 解释浏览器如何确定哪些元素与 CSS 选择器匹配。 316 | 317 | 这部分与上面关于编写高效的 CSS 有关。浏览器从最右边的选择器(关键选择器)根据关键选择器,浏览器从 DOM 中筛选出元素,然后向上遍历被选元素的父元素,判断是否匹配。选择器匹配语句链越短,浏览器的匹配速度越快。 318 | 319 | 例如,对于形如`p span`的选择器,浏览器首先找到所有``元素,并遍历它的父元素直到根元素以找到`

`元素。对于特定的``,只要找到一个`

`,就知道'`已经匹配并停止继续匹配。 320 | 321 | ###### 参考 322 | 323 | * https://stackoverflow.com/questions/5797014/why-do-browsers-match-css-selectors-from-right-to-left 324 | 325 | [[↑] 回到顶部](#css-问题) 326 | 327 | ### 描述伪元素及其用途。 328 | 329 | CSS 伪元素是添加到选择器的关键字,去选择元素的特定部分。它们可以用于装饰(`:first-line`,`:first-letter`)或将元素添加到标记中(与 content:...组合),而不必修改标记(`:before`,`:after`)。 330 | 331 | * `:first-line`和`:first-letter`可以用来修饰文字。 332 | * 上面提到的`.clearfix`方法中,使用`clear: both`来添加不占空间的元素。 333 | * 使用`:before`和`after`展示提示中的三角箭头。鼓励关注点分离,因为三角被视为样式的一部分,而不是真正的 DOM。如果不使用额外的 HTML 元素,只用 CSS 样式绘制三角形是不太可能的。 334 | 335 | ###### 参考 336 | 337 | * https://css-tricks.com/almanac/selectors/a/after-and-before/ 338 | 339 | [[↑] 回到顶部](#css-问题) 340 | 341 | ### 说说你对盒模型的理解,以及如何告知浏览器使用不同的盒模型渲染布局。 342 | 343 | CSS 盒模型描述了以文档树中的元素而生成的矩形框,并根据排版模式进行布局。每个盒子都有一个内容区域(例如文本,图像等)以及周围可选的`padding`、`border`和`margin`区域。 344 | 345 | CSS 盒模型负责计算: 346 | 347 | * 块级元素占用多少空间。 348 | * 边框是否重叠,边距是否合并。 349 | * 盒子的尺寸。 350 | 351 | 盒模型有以下规则: 352 | 353 | * 块级元素的大小由`width`、`height`、`padding`、`border`和`margin`决定。 354 | * 如果没有指定`height`,则块级元素的高度等于其包含子元素的内容高度加上`padding`(除非有浮动元素,请参阅下文)。 355 | * 如果没有指定`width`,则非浮动块级元素的宽度等于其父元素的宽度减去父元素的`padding`。 356 | * 元素的`height`是由内容的`height`来计算的。 357 | * 元素的`width`是由内容的`width`来计算的。 358 | * 默认情况下,`padding`和`border`不是元素`width`和`height`的组成部分。 359 | 360 | ###### 参考 361 | 362 | * https://www.smashingmagazine.com/2010/06/the-principles-of-cross-browser-css-coding/#understand-the-css-box-model 363 | 364 | [[↑] 回到顶部](#css-问题) 365 | 366 | ### `* { box-sizing: border-box; }`会产生怎样的效果? 367 | 368 | * 元素默认应用了`box-sizing: content-box`,元素的宽高只会决定内容(content)的大小。 369 | * `box-sizing: border-box`改变计算元素`width`和`height`的方式,`border`和`padding`的大小也将计算在内。 370 | * 元素的`height` = 内容(content)的高度 + 垂直方向的`padding` + 垂直方向`border`的宽度 371 | * 元素的`width` = 内容(content)的宽度 + 水平方向的`padding` + 水平方向`border`的宽度 372 | 373 | [[↑] 回到顶部](#css-问题) 374 | 375 | ### `display`的属性值都有哪些? 376 | 377 | * `none`, `block`, `inline`, `inline-block`, `table`, `table-row`, `table-cell`, `list-item`. 378 | 379 | TODO 380 | 381 | [[↑] 回到顶部](#css-问题) 382 | 383 | ### `inline`和`inline-block`有什么区别? 384 | 385 | 我把`block`也加入其中,为了获得更好的比较。 386 | 387 | | | `block` | `inline-block` | `inline` | 388 | | ------------------------------- | ----------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | 389 | | 大小 | 填充其父容器的宽度。 | 取决于内容。 | 取决于内容。 | 390 | | 定位 | 从新的一行开始,并且不允许旁边有 HTML 元素(除非是`float`) | 与其他内容一起流动,并允许旁边有其他元素。 | 与其他内容一起流动,并允许旁边有其他元素。 | 391 | | 能否设置`width`和`height` | 能 | 能 | 不能。 设置会被忽略。 | 392 | | 可以使用`vertical-align`对齐 | 不可以 | 可以 | 可以 | 393 | | 边距(margin)和填充(padding) | 各个方向都存在 | 各个方向都存在 | 只有水平方向存在。垂直方向会被忽略。 尽管`border`和`padding`在`content`周围,但垂直方向上的空间取决于'line-height' | 394 | | 浮动(float) | - | - | 就像一个`block`元素,可以设置垂直边距和填充。 | 395 | 396 | [[↑] 回到顶部](#css-问题) 397 | 398 | ### `relative`、`fixed`、`absolute`和`static`四种定位有什么区别? 399 | 400 | 经过定位的元素,其`position`属性值必然是`relative`、`absolute`、`fixed`或`sticky`。 401 | 402 | * `static`:默认定位属性值。该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。 403 | * `relative`:该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。 404 | * `absolute`:不为元素预留空间,通过指定元素相对于最近的非 static 定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。 405 | * `fixed`:不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed 属性会创建新的层叠上下文。当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先。 406 | * `sticky`:盒位置根据正常流计算(这称为正常流动中的位置),然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。在所有情况下(即便被定位元素为 `table` 时),该元素定位均不对后续元素造成影响。当元素 B 被粘性定位时,后续元素的位置仍按照 B 未定位时的位置来确定。`position: sticky` 对 `table` 元素的效果与 `position: relative` 相同。 407 | 408 | ###### 参考 409 | 410 | * https://developer.mozilla.org/en/docs/Web/CSS/position 411 | 412 | [[↑] 回到顶部](#css-问题) 413 | 414 | ### 你使用过哪些现有的 CSS 框架?你是如何改进它们的? 415 | 416 | * **Bootstrap**: 更新周期缓慢。Bootstrap 4 已经处于 alpha 版本将近两年了。添加了在页面中广泛使用的微调按钮组件。 417 | * **Semantic UI**:源代码结构使得自定义主题很难理解。非常规主题系统的使用体验很差。外部库的路径需要硬编码(hard code)配置。变量重新赋值没有 Bootstrap 设计得好。 418 | * **Bulma**: 需要很多非语义的类和标记,显得很多余。不向后兼容,以至于升级版本后,会破坏应用的正常运行。 419 | 420 | [[↑] 回到顶部](#css-问题) 421 | 422 | ### 你了解 CSS Flexbox 和 Grid 吗? 423 | 424 | 了解。Flexbox 主要用于一维布局,而 Grid 则用于二维布局。 425 | 426 | Flexbox 解决了 CSS 中的许多常见问题,例如容器中元素的垂直居中,粘性定位(sticky)的页脚等。Bootstrap 和 Bulma 基于 Flexbox,这是创建布局的推荐方式。我之前曾使用过 Flexbox,但在使用`flex-grow`时遇到了一些浏览器不兼容问题(Safari),我必须使用`inline-blocks`和手动计算百分比宽度,来重写我的代码,这种体验不是很好。 427 | 428 | Grid 创建基于栅格的布局,是迄今为止最直观的方法(最好是!),但目前浏览器支持并不广泛。 429 | 430 | ###### 参考 431 | 432 | * https://philipwalton.github.io/solved-by-flexbox/ 433 | 434 | [[↑] 回到顶部](#css-问题) 435 | 436 | ### 请解释在编写网站时,响应式与移动优先的区别。 437 | 438 | TODO 439 | 440 | [[↑] 回到顶部](#css-问题) 441 | 442 | ### 响应式设计与自适应设计有何不同? 443 | 444 | 响应式设计和自适应设计都以提高不同设备间的用户体验为目标,根据视窗大小、分辨率、使用环境和控制方式等参数进行优化调整。 445 | 446 | 响应式设计的适应性原则:网站应该凭借一份代码,在各种设备上都有良好的显示和使用效果。响应式网站通过使用媒体查询,自适应栅格和响应式图片,基于多种因素进行变化,创造出优良的用户体验。就像一个球通过膨胀和收缩,来适应不同大小的篮圈。 447 | 448 | 自适应设计更像是渐进式增强的现代解释。与响应式设计单一地去适配不同,自适应设计通过检测设备和其他特征,从早已定义好的一系列视窗大小和其他特性中,选出最恰当的功能和布局。与使用一个球去穿过各种的篮筐不同,自适应设计允许使用多个球,然后根据不同的篮筐大小,去选择最合适的一个。 449 | 450 | ###### 参考 451 | 452 | * https://developer.mozilla.org/en-US/docs/Archive/Apps/Design/UI_layout_basics/Responsive_design_versus_adaptive_design 453 | * http://mediumwell.com/responsive-adaptive-mobile/ 454 | * https://css-tricks.com/the-difference-between-responsive-and-adaptive-design/ 455 | 456 | [[↑] 回到顶部](#css-问题) 457 | 458 | ### 你有没有使用过视网膜分辨率的图形?当中使用什么技术? 459 | 460 | 我倾向于使用更高分辨率的图形(显示尺寸的两倍)来处理视网膜显示。更好的方法是使用媒体查询,像`@media only screen and (min-device-pixel-ratio: 2) { ... }`,然后改变`background-image`。 461 | 462 | 对于图标类的图形,我会尽可能使用 svg 和图标字体,因为它们在任何分辨率下,都能被渲染得十分清晰。 463 | 464 | 还有一种方法是,在检查了`window.devicePixelRatio`的值后,利用 JavaScript 将``的`src`属性修改,用更高分辨率的版本进行替换。 465 | 466 | ###### 参考 467 | 468 | * https://www.sitepoint.com/css-techniques-for-retina-displays/ 469 | 470 | [[↑] 回到顶部](#css-问题) 471 | 472 | ### 什么情况下,用`translate()`而不用绝对定位?什么时候,情况相反。 473 | 474 | `translate()`是`transform`的一个值。改变`transform`或`opacity`不会触发浏览器重新布局(reflow)或重绘(repaint),只会触发复合(compositions)。而改变绝对定位会触发重新布局,进而触发重绘和复合。`transform`使浏览器为元素创建一个 GPU 图层,但改变绝对定位会使用到 CPU。 因此`translate()`更高效,可以缩短平滑动画的绘制时间。 475 | 476 | 当使用`translate()`时,元素仍然占据其原始空间(有点像`position:relative`),这与改变绝对定位不同。 477 | 478 | ###### 参考 479 | 480 | * https://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/ 481 | 482 | [[↑] 回到顶部](#css-问题) 483 | 484 | ### 其他答案 485 | 486 | * https://neal.codes/blog/front-end-interview-css-questions 487 | * https://quizlet.com/28293152/front-end-interview-questions-css-flash-cards/ 488 | * http://peterdoes.it/2015/12/03/a-personal-exercise-front-end-job-interview-questions-and-my-answers-all/ 489 | 490 | ### CSS选择器有哪些 491 | 492 | 1. ***通用选择器**:选择所有元素,**不参与计算优先级**,兼容性IE6+ 493 | 2. **#X id选择器**:选择id值为X的元素,兼容性:IE6+ 494 | 3. **.X 类选择器**: 选择class包含X的元素,兼容性:IE6+ 495 | 4. **X Y后代选择器**: 选择满足X选择器的后代节点中满足Y选择器的元素,兼容性:IE6+ 496 | 5. **X 元素选择器**: 选择标所有签为X的元素,兼容性:IE6+ 497 | 6. **:link,:visited,:focus,:hover,:active链接状态**: 选择特定状态的链接元素,顺序LoVe HAte,兼容性: IE4+ 498 | 7. **X + Y直接兄弟选择器**:在**X之后第一个兄弟节点**中选择满足Y选择器的元素,兼容性: IE7+ 499 | 8. **X > Y子选择器**: 选择X的子元素中满足Y选择器的元素,兼容性: IE7+ 500 | 9. **X ~ Y兄弟**: 选择**X之后所有兄弟节点**中满足Y选择器的元素,兼容性: IE7+ 501 | 10. **[attr]**:选择所有设置了attr属性的元素,兼容性IE7+ 502 | 11. **[attr=value]**:选择属性值刚好为value的元素 503 | 12. **[attr~=value]**:选择属性值为空白符分隔,其中一个的值刚好是value的元素 504 | 13. **[attr|=value]**:选择属性值刚好为value或者value-开头的元素 505 | 14. **[attr^=value]**:选择属性值以value开头的元素 506 | 15. **[attr$=value]**:选择属性值以value结尾的元素 507 | 16. **[attr*=value]**:选择属性值中包含value的元素 508 | 17. **[:checked]**:选择单选框,复选框,下拉框中选中状态下的元素,兼容性:IE9+ 509 | 18. **X:after, X::after**:after伪元素,选择元素虚拟子元素(元素的最后一个子元素),CSS3中::表示伪元素。兼容性:after为IE8+,::after为IE9+ 510 | 18. **:hover**:鼠标移入状态的元素,兼容性a标签IE4+, 所有元素IE7+ 511 | 19. **:not(selector)**:选择不符合selector的元素。**不参与计算优先级**,兼容性:IE9+ 512 | 20. **::first-letter**:伪元素,选择块元素第一行的第一个字母,兼容性IE5.5+ 513 | 21. **::first-line**:伪元素,选择块元素的第一行,兼容性IE5.5+ 514 | 22. **:nth-child(an + b)**:伪类,选择前面有an + b - 1个兄弟节点的元素,其中n 515 | >= 0, 兼容性IE9+ 516 | 23. **:nth-last-child(an + b)**:伪类,选择后面有an + b - 1个兄弟节点的元素 517 | 其中n >= 0,兼容性IE9+ 518 | 24. **X:nth-of-type(an+b)**:伪类,X为选择器,**解析得到元素标签**,选择**前面**有an + b - 1个**相同标签**兄弟节点的元素。兼容性IE9+ 519 | 25. **X:nth-last-of-type(an+b)**:伪类,X为选择器,解析得到元素标签,选择**后面**有an+b-1个相同**标签**兄弟节点的元素。兼容性IE9+ 520 | 26. **X:first-child**:伪类,选择满足X选择器的元素,且这个元素是其父节点的第一个子元素。兼容性IE7+ 521 | 27. **X:last-child**:伪类,选择满足X选择器的元素,且这个元素是其父节点的最后一个子元素。兼容性IE9+ 522 | 28. **X:only-child**:伪类,选择满足X选择器的元素,且这个元素是其父元素的唯一子元素。兼容性IE9+ 523 | 29. **X:only-of-type**:伪类,选择X选择的元素,**解析得到元素标签**,如果该元素没有相同类型的兄弟节点时选中它。兼容性IE9+ 524 | 30. **X:first-of-type**:伪类,选择X选择的元素,**解析得到元素标签**,如果该元素 525 | 是此此类型元素的第一个兄弟。选中它。兼容性IE9+ 526 | 527 | 528 | ### css sprite是什么,有什么优缺点 529 | 530 | 概念:将多个小图片拼接到一个图片中。通过background-position和元素尺寸调节需要显示的背景图案。 531 | 532 | 优点: 533 | 534 | 1. 减少HTTP请求数,极大地提高页面加载速度 535 | 2. 增加图片信息重复度,提高压缩比,减少图片大小 536 | 3. 更换风格方便,只需在一张或几张图片上修改颜色或样式即可实现 537 | 538 | 缺点: 539 | 540 | 1. 图片合并麻烦 541 | 2. 维护麻烦,修改一个图片可能需要从新布局整个图片,样式 542 | 543 | 544 | ### `display: none;`与`visibility: hidden;`的区别 545 | 联系:它们都能让元素不可见 546 | 547 | 区别: 548 | 549 | 1. display:none;会让元素完全从渲染树中消失,渲染的时候不占据任何空间;visibility: hidden;不会让元素从渲染树消失,渲染师元素继续占据空间,只是内容不可见 550 | 2. display: none;是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示;visibility: hidden;是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式 551 | 3. 修改常规流中元素的display通常会造成文档重排。修改visibility属性只会造成本元素的重绘。 552 | 4. 读屏器不会读取display: none;元素内容;会读取visibility: hidden;元素内容 553 | 554 | ### css hack原理及常用hack 555 | 556 | 原理:利用**不同浏览器对CSS的支持和解析结果不一样**编写针对特定浏览器样式。常见的hack有1)属性hack。2)选择器hack。3)IE条件注释 557 | 558 | - IE条件注释:适用于[IE5, IE9]常见格式如下 559 | 560 | ``` 561 | 564 | ``` 565 | 566 | - 选择器hack:不同浏览器对选择器的支持不一样 567 | 568 | ``` 569 | /***** Selector Hacks ******/ 570 | 571 | /* IE6 and below */ 572 | * html #uno { color: red } 573 | 574 | /* IE7 */ 575 | *:first-child+html #dos { color: red } 576 | 577 | /* IE7, FF, Saf, Opera */ 578 | html>body #tres { color: red } 579 | 580 | /* IE8, FF, Saf, Opera (Everything but IE 6,7) */ 581 | html>/**/body #cuatro { color: red } 582 | 583 | /* Opera 9.27 and below, safari 2 */ 584 | html:first-child #cinco { color: red } 585 | 586 | /* Safari 2-3 */ 587 | html[xmlns*=""] body:last-child #seis { color: red } 588 | 589 | /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 590 | body:nth-of-type(1) #siete { color: red } 591 | 592 | /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 593 | body:first-of-type #ocho { color: red } 594 | 595 | /* saf3+, chrome1+ */ 596 | @media screen and (-webkit-min-device-pixel-ratio:0) { 597 | #diez { color: red } 598 | } 599 | 600 | /* iPhone / mobile webkit */ 601 | @media screen and (max-device-width: 480px) { 602 | #veintiseis { color: red } 603 | } 604 | 605 | /* Safari 2 - 3.1 */ 606 | html[xmlns*=""]:root #trece { color: red } 607 | 608 | /* Safari 2 - 3.1, Opera 9.25 */ 609 | *|html[xmlns*=""] #catorce { color: red } 610 | 611 | /* Everything but IE6-8 */ 612 | :root *> #quince { color: red } 613 | 614 | /* IE7 */ 615 | *+html #dieciocho { color: red } 616 | 617 | /* Firefox only. 1+ */ 618 | #veinticuatro, x:-moz-any-link { color: red } 619 | 620 | /* Firefox 3.0+ */ 621 | #veinticinco, x:-moz-any-link, x:default { color: red } 622 | ``` 623 | 624 | - 属性hack:不同浏览器解析bug或方法 625 | 626 | ``` 627 | /* IE6 */ 628 | #once { _color: blue } 629 | 630 | /* IE6, IE7 */ 631 | #doce { *color: blue; /* or #color: blue */ } 632 | 633 | /* Everything but IE6 */ 634 | #diecisiete { color/**/: blue } 635 | 636 | /* IE6, IE7, IE8 */ 637 | #diecinueve { color: blue\9; } 638 | 639 | /* IE7, IE8 */ 640 | #veinte { color/*\**/: blue\9; } 641 | 642 | /* IE6, IE7 -- acts as an !important */ 643 | #veintesiete { color: blue !ie; } /* string after ! can be anything */ 644 | ``` 645 | 646 | ### specified value,computed value,used value计算方法 647 | 648 | - specified value: 计算方法如下: 649 | 1. 如果样式表设置了一个值,使用这个值 650 | 2. 如果没有设置值,这个属性是继承属性,从父元素继承 651 | 3. 如果没设置,并且不是继承属性,使用css规范指定的初始值 652 | 653 | - computed value: 以specified value根据规范定义的行为进行计算,通常将相对值计算为绝对值,例如em根据font-size进行计算。一些使用百分数并且需要布局来决定最终值的属性,如width,margin。百分数就直接作为computed value。line-height的无单位值也直接作为computed value。这些值将在计算used value时得到绝对值。**computed value的主要作用是用于继承** 654 | 655 | - used value:属性计算后的最终值,对于大多数属性可以通过window.getComputedStyle获得,尺寸值单位为像素。以下属性依赖于布局, 656 | - background-position 657 | - bottom, left, right, top 658 | - height, width 659 | - margin-bottom, margin-left, margin-right, margin-top 660 | - min-height, min-width 661 | - padding-bottom, padding-left, padding-right, padding-top 662 | - text-indent 663 | 664 | ### `link`与`@import`的区别 665 | 666 | 1. ``link``是HTML方式, ``@import``是CSS方式 667 | 2. ``link``最大限度支持并行下载,``@import``过多嵌套导致串行下载,出现[FOUC](http://www.bluerobot.com/web/css/fouc.asp/) 668 | 4. ``link``可以通过``rel="alternate stylesheet"``指定候选样式 669 | 5. 浏览器对``link``支持早于``@import``,可以使用``@import``对老浏览器隐藏样式 670 | 6. ``@import``必须在样式规则之前,可以在css文件中引用其他文件 671 | 6. 总体来说:**[link优于@import](http://www.stevesouders.com/blog/2009/04/09/dont-use-import/)** 672 | 673 | ### ``display: block;``和``display: inline;``的区别 674 | 675 | ``block``元素特点: 676 | 677 | 1.处于常规流中时,如果``width``没有设置,会自动填充满父容器 678 | 2.可以应用``margin/padding`` 679 | 3.在没有设置高度的情况下会扩展高度以包含常规流中的子元素 680 | 4.处于常规流中时布局时在前后元素位置之间(独占一个水平空间) 681 | 5.忽略``vertical-align`` 682 | 683 | ``inline``元素特点 684 | 685 | 1.水平方向上根据``direction``依次布局 686 | 2.不会在元素前后进行换行 687 | 3.受``white-space``控制 688 | 4.``margin/padding``在竖直方向上无效,水平方向上有效 689 | 5.``width/height``属性对非替换行内元素无效,宽度由元素内容决定 690 | 6.非替换行内元素的行框高由``line-height``确定,替换行内元素的行框高由``height``,``margin``,``padding``,``border``决定 691 | 6.浮动或绝对定位时会转换为``block`` 692 | 7.``vertical-align``属性生效 693 | 694 | 695 | 696 | ### PNG,GIF,JPG的区别及如何选 697 | 参考资料: [选择正确的图片格式](http://www.yuiblog.com/blog/2008/11/04/imageopt-2/) 698 | **GIF**: 699 | 700 | 1. 8位像素,256色 701 | 2. 无损压缩 702 | 3. 支持简单动画 703 | 4. 支持boolean透明 704 | 5. 适合简单动画 705 | 706 | **JPEG**: 707 | 708 | 1. 颜色限于256 709 | 2. 有损压缩 710 | 3. 可控制压缩质量 711 | 4. 不支持透明 712 | 5. 适合照片 713 | 714 | **PNG**: 715 | 716 | 1. 有PNG8和truecolor PNG 717 | 2. PNG8类似GIF颜色上限为256,文件小,支持alpha透明度,无动画 718 | 3. 适合图标、背景、按钮 719 | 720 | ### CSS有哪些继承属性 721 | 722 | - 关于文字排版的属性如: 723 | + [font](https://developer.mozilla.org/en-US/docs/Web/CSS/font) 724 | + [word-break](https://developer.mozilla.org/en-US/docs/Web/CSS/word-break) 725 | + [letter-spacing](https://developer.mozilla.org/en-US/docs/Web/CSS/letter-spacing) 726 | + [text-align](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align) 727 | + [text-rendering](https://developer.mozilla.org/en-US/docs/Web/CSS/text-rendering) 728 | + [word-spacing](https://developer.mozilla.org/en-US/docs/Web/CSS/word-spacing) 729 | + [white-space](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space) 730 | + [text-indent](https://developer.mozilla.org/en-US/docs/Web/CSS/text-indent) 731 | + [text-transform](https://developer.mozilla.org/en-US/docs/Web/CSS/text-transform) 732 | + [text-shadow](https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow) 733 | - [line-height](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height) 734 | - [color](https://developer.mozilla.org/en-US/docs/Web/CSS/color) 735 | - [visibility](https://developer.mozilla.org/en-US/docs/Web/CSS/visibility) 736 | - [cursor](https://developer.mozilla.org/en-US/docs/Web/CSS/cursor) 737 | 738 | 739 | 740 | ### IE6浏览器有哪些常见的bug,缺陷或者与标准不一致的地方,如何解决 741 | 742 | - IE6不支持min-height,解决办法使用css hack: 743 | 744 | ``` 745 | .target { 746 | min-height: 100px; 747 | height: auto !important; 748 | height: 100px; // IE6下内容高度超过会自动扩展高度 749 | } 750 | ``` 751 | 752 | - ``ol``内``li``的序号全为1,不递增。解决方法:为li设置样式``display: list-item;`` 753 | 754 | - 未定位父元素``overflow: auto;``,包含``position: relative;``子元素,子元素高于父元素时会溢出。解决办法:1)子元素去掉``position: relative;``; 2)不能为子元素去掉定位时,父元素``position: relative;`` 755 | 756 | ``` 757 | 772 | 773 |

774 |
775 |
776 | ``` 777 | 778 | - IE6只支持``a``标签的``:hover``伪类,解决方法:使用js为元素监听mouseenter,mouseleave事件,添加类实现效果: 779 | 780 | ``` 781 | 787 | 788 |

aaaa bbbbbDDDDDDDDDDDd aaaa lkjlkjdf j

789 | 790 | 814 | ``` 815 | 816 | - IE5-8不支持``opacity``,解决办法: 817 | 818 | ``` 819 | .opacity { 820 | opacity: 0.4 821 | filter: alpha(opacity=60); /* for IE5-7 */ 822 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; /* for IE 8*/ 823 | } 824 | ``` 825 | 826 | - IE6在设置``height``小于``font-size``时高度值为``font-size``,解决办法:``font-size: 0;`` 827 | - IE6不支持PNG透明背景,解决办法: **IE6下使用gif图片** 828 | - IE6-7不支持``display: inline-block``解决办法:设置inline并触发hasLayout 829 | 830 | ``` 831 | display: inline-block; 832 | *display: inline; 833 | *zoom: 1; 834 | ``` 835 | 836 | - IE6下浮动元素在浮动方向上与父元素边界接触元素的外边距会加倍。解决办法: 837 | 1)使用padding控制间距。 838 | 2)浮动元素``display: inline;``这样解决问题且无任何副作用:css标准规定浮动元素display:inline会自动调整为block 839 | - 通过为块级元素设置宽度和左右margin为auto时,IE6不能实现水平居中,解决方法:为父元素设置``text-align: center;`` 840 | 841 | ### 容器包含若干浮动元素时如何清理(包含)浮动 842 | 843 | 1. 容器元素闭合标签前添加额外元素并设置``clear: both`` 844 | 2. 父元素触发块级格式化上下文(见块级可视化上下文部分) 845 | 3. 设置容器元素伪元素进行清理[推荐的清理浮动方法](http://nicolasgallagher.com/micro-clearfix-hack/) 846 | 847 | ``` 848 | /** 849 | * 在标准浏览器下使用 850 | * 1 content内容为空格用于修复opera下文档中出现 851 | * contenteditable属性时在清理浮动元素上下的空白 852 | * 2 使用display使用table而不是block:可以防止容器和 853 | * 子元素top-margin折叠,这样能使清理效果与BFC,IE6/7 854 | * zoom: 1;一致 855 | **/ 856 | 857 | .clearfix:before, 858 | .clearfix:after { 859 | content: " "; /* 1 */ 860 | display: table; /* 2 */ 861 | } 862 | 863 | .clearfix:after { 864 | clear: both; 865 | } 866 | 867 | /** 868 | * IE 6/7下使用 869 | * 通过触发hasLayout实现包含浮动 870 | **/ 871 | .clearfix { 872 | *zoom: 1; 873 | } 874 | ``` 875 | 876 | ### 什么是FOUC?如何避免 877 | Flash Of Unstyled Content:用户定义样式表加载之前浏览器使用默认样式显示文档,用户样式加载渲染之后再从新显示文档,造成页面闪烁。**解决方法**:把样式表放到文档的`head` 878 | 879 | ### 如何创建块级格式化上下文(block formatting context),BFC有什么用 880 | 创建规则: 881 | 882 | 1. 根元素 883 | 2. 浮动元素(``float``不是``none``) 884 | 3. 绝对定位元素(``position``取值为``absolute``或``fixed``) 885 | 4. ``display``取值为``inline-block``,``table-cell``, ``table-caption``,``flex``, ``inline-flex``之一的元素 886 | 5. ``overflow``不是``visible``的元素 887 | 888 | 889 | 作用: 890 | 891 | 1. 可以包含浮动元素 892 | 2. 不被浮动元素覆盖 893 | 3. 阻止父子元素的margin折叠 894 | 895 | ### display,float,position的关系 896 | 897 | 1. 如果``display``为none,那么position和float都不起作用,这种情况下元素不产生框 898 | 2. 否则,如果position值为absolute或者fixed,框就是绝对定位的,float的计算值为none,display根据下面的表格进行调整。 899 | 3. 否则,如果float不是none,框是浮动的,display根据下表进行调整 900 | 4. 否则,如果元素是根元素,display根据下表进行调整 901 | 5. 其他情况下display的值为指定值 902 | 总结起来:**绝对定位、浮动、根元素都需要调整``display``** 903 | ![display转换规则](/img/display-adjust.png) 904 | 905 | ### 外边距折叠(collapsing margins) 906 | 毗邻的两个或多个``margin``会合并成一个margin,叫做外边距折叠。规则如下: 907 | 908 | 1. 两个或多个毗邻的普通流中的块元素垂直方向上的margin会折叠 909 | 2. 浮动元素/inline-block元素/绝对定位元素的margin不会和垂直方向上的其他元素的margin折叠 910 | 3. 创建了块级格式化上下文的元素,不会和它的子元素发生margin折叠 911 | 4. 元素自身的margin-bottom和margin-top相邻时也会折叠 912 | 913 | ### 如何确定一个元素的包含块(containing block) 914 | 915 | 1. 根元素的包含块叫做初始包含块,在连续媒体中他的尺寸与viewport相同并且anchored at the canvas origin;对于paged media,它的尺寸等于page area。初始包含块的direction属性与根元素相同。 916 | 2. ``position``为``relative``或者``static``的元素,它的包含块由最近的块级(``display``为``block``,``list-item``, ``table``)祖先元素的**内容框**组成 917 | 3. 如果元素``position``为``fixed``。对于连续媒体,它的包含块为viewport;对于paged media,包含块为page area 918 | 4. 如果元素``position``为``absolute``,它的包含块由祖先元素中最近一个``position``为``relative``,``absolute``或者``fixed``的元素产生,规则如下: 919 | - 如果祖先元素为行内元素,the containing block is the bounding box around the **padding boxes** of the first and the last inline boxes generated for that element. 920 | - 其他情况下包含块由祖先节点的**padding edge**组成 921 | 922 | 如果找不到定位的祖先元素,包含块为**初始包含块** 923 | 924 | ### stacking context,布局规则 925 | z轴上的默认层叠顺序如下(从下到上): 926 | 927 | 1. 根元素的边界和背景 928 | 2. 常规流中的元素按照html中顺序 929 | 3. 浮动块 930 | 4. positioned元素按照html中出现顺序 931 | 932 | 如何创建stacking context: 933 | 934 | 1. 根元素 935 | 2. z-index不为auto的定位元素 936 | 3. a flex item with a z-index value other than 'auto' 937 | 4. opacity小于1的元素 938 | 5. 在移动端webkit和chrome22+,z-index为auto,position: fixed也将创建新的stacking context 939 | 940 | ### 如何水平居中一个元素 941 | - 如果需要居中的元素为**常规流中inline元素**,为父元素设置`text-align: center;`即可实现 942 | - 如果需要居中的元素为**常规流中block元素**,1)为元素设置宽度,2)设置左右margin为auto。3)IE6下需在父元素上设置`text-align: center;`,再给子元素恢复需要的值 943 | 944 | ``` 945 | 946 |
947 | aaaaaa aaaaaa a a a a a a a a 948 |
949 | 950 | 951 | 964 | ``` 965 | 966 | - 如果需要居中的元素为**浮动元素**,1)为元素设置宽度,2)`position: relative;`,3)浮动方向偏移量(left或者right)设置为50%,4)浮动方向上的margin设置为元素宽度一半乘以-1 967 | 968 | ``` 969 | 970 |
971 | aaaaaa aaaaaa a a a a a a a a 972 |
973 | 974 | 975 | 990 | ``` 991 | 992 | - 如果需要居中的元素为**绝对定位元素**,1)为元素设置宽度,2)偏移量设置为50%,3)偏移方向外边距设置为元素宽度一半乘以-1 993 | 994 | ``` 995 | 996 |
997 | aaaaaa aaaaaa a a a a a a a a 998 |
999 | 1000 | 1001 | 1016 | ``` 1017 | 1018 | - 如果需要居中的元素为**绝对定位元素**,1)为元素设置宽度,2)设置左右偏移量都为0,3)设置左右外边距都为auto 1019 | 1020 | ``` 1021 | 1022 |
1023 | aaaaaa aaaaaa a a a a a a a a 1024 |
1025 | 1026 | 1027 | 1043 | ``` 1044 | 1045 | ### 如何竖直居中一个元素 1046 | 参考资料:[6 Methods For Vertical Centering With CSS](http://www.vanseodesign.com/css/vertical-centering/)。 [盘点8种CSS实现垂直居中](http://blog.csdn.net/freshlover/article/details/11579669) 1047 | 1048 | - 需要居中元素为**单行文本**,为包含文本的元素设置大于`font-size`的`line-height`: 1049 | 1050 | ``` 1051 |

center text

1052 | 1053 | 1058 | ``` 1059 | 1060 | -------------------------------------------------------------------------------- /html/html-questions.md: -------------------------------------------------------------------------------- 1 | # HTML 问题 2 | 3 | 欢迎提出 PR 进行建议和指正! 4 | 5 | * [`DOCTYPE`有什么用?](#doctype有什么用) 6 | * [如何提供包含多种语言内容的页面?](#如何提供包含多种语言内容的页面) 7 | * [在设计开发多语言网站时,需要留心哪些事情?](#在设计开发多语言网站时需要留心哪些事情) 8 | * [什么是`data-`属性?](#什么是data-属性) 9 | * [将 HTML5 看作成开放的网络平台,什么是 HTML5 的基本构件(building block)?](#将-html5-看作成开放的网络平台什么是-html5-的基本构件building-block) 10 | * [请描述`cookie`、`sessionStorage`和`localStorage`的区别。](#请描述cookiesessionstorage和localstorage的区别) 11 | * [请描述` 484 | 485 | 486 | ``` 487 | 488 | ```js 489 | // 文件加载自 https://example.com?callback=printData 490 | printData({ name: 'Yang Shun' }); 491 | ``` 492 | 493 | 客户端必须在其全局范围内具有`printData`函数,并且在收到来自跨域的响应时,该函数将由客户端执行。 494 | 495 | JSONP 可能具有一些安全隐患。由于 JSONP 是纯 JavaScript 实现,它可以完成 JavaScript 所能做的一切,因此需要信任 JSONP 数据的提供者。 496 | 497 | 现如今,[跨来源资源共享(CORS)](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) 是推荐的主流方式,JSONP 已被视为一种比较 hack 的方式。 498 | 499 | ###### 参考 500 | 501 | * https://stackoverflow.com/a/2067584/1751946 502 | 503 | [[↑] 回到顶部](#js-问题) 504 | 505 | ### 你使用过 JavaScript 模板吗?用过什么相关的库? 506 | 507 | 使用过。Handlebars、Underscore、Lodash、AngularJS 和 JSX。我不喜欢 AngularJS 中的模板,因为它在指令中大量使用了字符串,并且书写错误会被忽略。JSX 是我的新宠,因为它更接近 JavaScript,几乎没有什么学习成本。现在,可以使用 ES2015 模板字符串快速创建模板,而不需依赖第三方代码。 508 | 509 | ```js 510 | const template = `
My name is: ${name}
`; 511 | ``` 512 | 513 | 但是,请注意上述方法中可能存在的 XSS,因为内容不会被转义,与模板库不同。 514 | 515 | [[↑] 回到顶部](#js-问题) 516 | 517 | ### 请解释变量提升(hoisting)。 518 | 519 | 变量提升(hoisting)是用于解释代码中变量声明行为的术语。使用`var`关键字声明或初始化的变量,会将声明语句“提升”到当前作用域的顶部。 但是,只有声明才会触发提升,赋值语句(如果有的话)将保持原样。我们用几个例子来解释一下。 520 | 521 | ```js 522 | // 用 var 声明得到提升 523 | console.log(foo); // undefined 524 | var foo = 1; 525 | console.log(foo); // 1 526 | 527 | // 用 let/const 声明不会提升 528 | console.log(bar); // ReferenceError: bar is not defined 529 | let bar = 2; 530 | console.log(bar); // 2 531 | ``` 532 | 533 | 函数声明会使函数体提升,但函数表达式(以声明变量的形式书写)只有变量声明会被提升。 534 | 535 | ```js 536 | // 函数声明 537 | console.log(foo); // [Function: foo] 538 | foo(); // 'FOOOOO' 539 | function foo() { 540 | console.log('FOOOOO'); 541 | } 542 | console.log(foo); // [Function: foo] 543 | 544 | // 函数表达式 545 | console.log(bar); // undefined 546 | bar(); // Uncaught TypeError: bar is not a function 547 | var bar = function() { 548 | console.log('BARRRR'); 549 | }; 550 | console.log(bar); // [Function: bar] 551 | ``` 552 | 553 | [[↑] 回到顶部](#js-问题) 554 | 555 | ### 请描述事件冒泡。 556 | 557 | 当一个事件在 DOM 元素上触发时,如果有事件监听器,它将尝试处理该事件,然后事件冒泡到其父级元素,并发生同样的事情。最后直到事件到达祖先元素。事件冒泡是实现事件委托的原理(event delegation)。 558 | 559 | [[↑] 回到顶部](#js-问题) 560 | 561 | ### “attribute” 和 “property” 之间有什么区别? 562 | 563 | “Attribute” 是在 HTML 中定义的,而 “property” 是在 DOM 上定义的。为了说明区别,假设我们在 HTML 中有一个文本框:``。 564 | 565 | ```js 566 | const input = document.querySelector('input'); 567 | console.log(input.getAttribute('value')); // Hello 568 | console.log(input.value); // Hello 569 | ``` 570 | 571 | 但是在文本框中键入“ World!”后: 572 | 573 | ```js 574 | console.log(input.getAttribute('value')); // Hello 575 | console.log(input.value); // Hello World! 576 | ``` 577 | 578 | ###### 参考 579 | 580 | * https://stackoverflow.com/questions/6003819/properties-and-attributes-in-html 581 | 582 | [[↑] 回到顶部](#js-问题) 583 | 584 | ### 为什么扩展 JavaScript 内置对象是不好的做法? 585 | 586 | 扩展 JavaScript 内置(原生)对象意味着将属性或方法添加到其`prototype`中。虽然听起来很不错,但事实上这样做很危险。想象一下,你的代码使用了一些库,它们通过添加相同的 contains 方法来扩展`Array.prototype`,如果这两个方法的行为不相同,那么这些实现将会相互覆盖,你的代码将不能正常运行。 587 | 588 | 扩展内置对象的唯一使用场景是创建 polyfill,本质上为老版本浏览器缺失的方法提供自己的实现,该方法是由 JavaScript 规范定义的。 589 | 590 | ###### 参考 591 | 592 | * http://lucybain.com/blog/2014/js-extending-built-in-objects/ 593 | 594 | [[↑] 回到顶部](#js-问题) 595 | 596 | ### document 中的`load`事件和`DOMContentLoaded`事件之间的区别是什么? 597 | 598 | 当初始的 HTML 文档被完全加载和解析完成之后,`DOMContentLoaded`事件被触发,而无需等待样式表、图像和子框架的完成加载。 599 | 600 | `window`的`load`事件仅在 DOM 和所有相关资源全部完成加载后才会触发。 601 | 602 | ###### 参考 603 | 604 | * https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded 605 | * https://developer.mozilla.org/en-US/docs/Web/Events/load 606 | 607 | [[↑] 回到顶部](#js-问题) 608 | 609 | ### `==`和`===`的区别是什么? 610 | 611 | `==`是抽象相等运算符,而`===`是严格相等运算符。`==`运算符是在进行必要的类型转换后,再比较。`===`运算符不会进行类型转换,所以如果两个值不是相同的类型,会直接返回`false`。使用`==`时,可能发生一些特别的事情,例如: 612 | 613 | ```js 614 | 1 == '1'; // true 615 | 1 == [1]; // true 616 | 1 == true; // true 617 | 0 == ''; // true 618 | 0 == '0'; // true 619 | 0 == false; // true 620 | ``` 621 | 622 | 我的建议是从不使用`==`运算符,除了方便与`null`或`undefined`比较时,`a == null`如果`a`为`null`或`undefined`将返回`true`。 623 | 624 | ```js 625 | var a = null; 626 | console.log(a == null); // true 627 | console.log(a == undefined); // true 628 | ``` 629 | 630 | ###### 参考 631 | 632 | * https://stackoverflow.com/questions/359494/which-equals-operator-vs-should-be-used-in-javascript-comparisons 633 | 634 | [[↑] 回到顶部](#js-问题) 635 | 636 | ### 请解释关于 JavaScript 的同源策略。 637 | 638 | 同源策略可防止 JavaScript 发起跨域请求。源被定义为 URI、主机名和端口号的组合。此策略可防止页面上的恶意脚本通过该页面的文档对象模型,访问另一个网页上的敏感数据。 639 | 640 | ###### 参考 641 | 642 | * https://en.wikipedia.org/wiki/Same-origin_policy 643 | 644 | [[↑] 回到顶部](#js-问题) 645 | 646 | ### 请使下面的语句生效: 647 | 648 | ```js 649 | duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5] 650 | ``` 651 | 652 | ```js 653 | function duplicate(arr) { 654 | return arr.concat(arr); 655 | } 656 | 657 | duplicate([1, 2, 3, 4, 5]); // [1,2,3,4,5,1,2,3,4,5] 658 | ``` 659 | 660 | [[↑] 回到顶部](#js-问题) 661 | 662 | ### 请说明三元表达式中“三元”这个词代表什么? 663 | 664 | “三元”表示接受三个操作数:判断条件,`then`表达式和`else`表达式。三元表达式不是 JavaScript 特有的,我不知道这个问题为什么会出现在这里。 665 | 666 | ###### 参考 667 | 668 | * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator 669 | 670 | [[↑] 回到顶部](#js-问题) 671 | 672 | ### 什么是`"use strict";`?使用它有什么优缺点? 673 | 674 | 'use strict' 是用于对整个脚本或单个函数启用严格模式的语句。严格模式是可选择的一个限制 JavaScript 的变体一种方式 。 675 | 676 | **优点:** 677 | 678 | * 无法再意外创建全局变量。 679 | * 会使引起静默失败(silently fail,即:不报错也没有任何效果)的赋值操抛出异常。 680 | * 试图删除不可删除的属性时会抛出异常(之前这种操作不会产生任何效果)。 681 | * 要求函数的参数名唯一。 682 | * 全局作用域下,`this`的值为`undefined`。 683 | * 捕获了一些常见的编码错误,并抛出异常。 684 | * 禁用令人困惑或欠佳的功能。 685 | 686 | **缺点:** 687 | 688 | * 缺失许多开发人员已经习惯的功能。 689 | * 无法访问`function.caller`和`function.arguments`。 690 | * 以不同严格模式编写的脚本合并后可能导致问题。 691 | 692 | 总的来说,我认为利大于弊,我从来不使用严格模式禁用的功能,因此我推荐使用严格模式。 693 | 694 | ###### 参考 695 | 696 | * http://2ality.com/2011/10/strict-mode-hatred.html 697 | * http://lucybain.com/blog/2014/js-use-strict/ 698 | 699 | [[↑] 回到顶部](#js-问题) 700 | 701 | ### 创建一个循环,从 1 迭代到 100,`3`的倍数时输出 "fizz",`5`的倍数时输出 "buzz",同时为`3`和`5`的倍数时输出 "fizzbuzz"。 702 | 703 | 来自 [Paul Irish](https://gist.github.com/jaysonrowe/1592432#gistcomment-790724)的 FizzBuzz。 704 | 705 | ```js 706 | for (let i = 1; i <= 100; i++) { 707 | let f = i % 3 == 0, 708 | b = i % 5 == 0; 709 | console.log(f ? (b ? 'FizzBuzz' : 'Fizz') : b ? 'Buzz' : i); 710 | } 711 | ``` 712 | 713 | 我不建议你在面试时写上面的代码。只要写得清晰即可。关于更多千奇百怪的 FizzBuzz 实现,请查看下面的参考链接。 714 | 715 | ###### 参考 716 | 717 | * https://gist.github.com/jaysonrowe/1592432 718 | 719 | [[↑] 回到顶部](#js-问题) 720 | 721 | ### 为什么不要使用全局作用域? 722 | 723 | 每个脚本都可以访问全局作用域,如果人人都使用全局命名空间来定义自己的变量,肯定会发生冲突。使用模块模式(IIFE)将变量封装在本地命名空间中。 724 | 725 | [[↑] 回到顶部](#js-问题) 726 | 727 | ### 为什么要使用`load`事件?这个事件有什么缺点吗?你知道一些代替方案吗,为什么使用它们? 728 | 729 | 在文档装载完成后会触发`load`事件。此时,在文档中的所有对象都在 DOM 中,所有图像、脚本、链接和子框架都完成了加载。 730 | 731 | DOM 事件`DOMContentLoaded`将在页面的 DOM 构建完成后触发,但不要等待其他资源完成加载。如果在初始化之前不需要装入整个页面,这个事件是使用首选。 732 | 733 | TODO. 734 | 735 | ###### 参考 736 | 737 | * https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload 738 | 739 | [[↑] 回到顶部](#js-问题) 740 | 741 | ### 请解释单页应用是什么,如何使其对 SEO 友好。 742 | 743 | 以下摘自 [Grab Front End Guide](https://github.com/grab/front-end-guide),碰巧的是,这正是我自己写的! 744 | 745 | 现如今,Web 开发人员将他们构建的产品称为 Web 应用,而不是网站。虽然这两个术语之间没有严格的区别,但网络应用往往具有高度的交互性和动态性,允许用户执行操作并接收他们的操作响应。在过去,浏览器从服务器接收 HTML 并渲染。当用户导航到其它 URL 时,需要整页刷新,服务器会为新页面发送新的 HTML。这被称为服务器端渲染。 746 | 747 | 然而,在现代的 SPA 中,客户端渲染取而代之。浏览器从服务器加载初始页面、整个应用程序所需的脚本(框架、库、应用代码)和样式表。当用户导航到其他页面时,不会触发页面刷新。该页面的 URL 通过 [HTML5 History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) 进行更新。浏览器通过 [AJAX](https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started) 请求向服务器检索新页面所需的数据(通常采用 JSON 格式)。然后,SPA 通过 JavaScript 来动态更新页面,这些 JavaScript 在初始页面加载时已经下载。这种模式类似于原生移动应用的工作方式。 748 | 749 | **好处:** 750 | 751 | * 用户感知响应更快,用户切换页面时,不再看到因页面刷新而导致的白屏。 752 | * 对服务器进行的 HTTP 请求减少,因为对于每个页面加载,不必再次下载相同的资源。 753 | * 客户端和服务器之间的关注点分离。可以为不同平台(例如手机、聊天机器人、智能手表)建立新的客户端,而无需修改服务器代码。只要 API 没有修改,可以单独修改客户端和服务器上的代码。 754 | 755 | **坏处:** 756 | 757 | * 由于加载了多个页面所需的框架、应用代码和资源,导致初始页面加载时间较长。 758 | * 服务器还需要进行额外的工作,需要将所有请求路由配置到单个入口点,然后由客户端接管路由。 759 | * SPA 依赖于 JavaScript 来呈现内容,但并非所有搜索引擎都在抓取过程中执行 JavaScript,他们可能会在你的页面上看到空的内容。这无意中损害了应用的搜索引擎优化(SEO)。然而,当你构建应用时,大多数情况下,搜索引擎优化并不是最重要的因素,因为并非所有内容都需要通过搜索引擎进行索引。为了解决这个问题,可以在服务器端渲染你的应用,或者使用诸如 [Prerender](https://prerender.io/) 的服务来“在浏览器中呈现你的 javascript,保存静态 HTML,并将其返回给爬虫”。 760 | 761 | ###### 参考 762 | 763 | * https://github.com/grab/front-end-guide#single-page-apps-spas 764 | * http://stackoverflow.com/questions/21862054/single-page-app-advantages-and-disadvantages 765 | * http://blog.isquaredsoftware.com/presentations/2016-10-revolution-of-web-dev/ 766 | * https://medium.freecodecamp.com/heres-why-client-side-rendering-won-46a349fadb52 767 | 768 | [[↑] 回到顶部](#js-问题) 769 | 770 | ### 你对 Promises 及其 polyfill 的掌握程度如何? 771 | 772 | 掌握它的工作原理。`Promise`是一个可能在未来某个时间产生结果的对象:操作成功的结果或失败的原因(例如发生网络错误)。 `Promise`可能处于以下三种状态之一:fulfilled、rejected 或 pending。 用户可以对`Promise`添加回调函数来处理操作成功的结果或失败的原因。 773 | 774 | 一些常见的 polyfill 是`$.deferred`、Q 和 Bluebird,但不是所有的 polyfill 都符合规范。ES2015 支持 Promises,现在通常不需要使用 polyfills。 775 | 776 | ###### 参考 777 | 778 | * https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261 779 | 780 | [[↑] 回到顶部](#js-问题) 781 | 782 | ### `Promise`代替回调函数有什么优缺点? 783 | 784 | **优点:** 785 | 786 | * 避免可读性极差的回调地狱。 787 | * 使用`.then()`编写的顺序异步代码,既简单又易读。 788 | * 使用`Promise.all()`编写并行异步代码变得很容易。 789 | 790 | **缺点:** 791 | 792 | * 轻微地增加了代码的复杂度(这点存在争议)。 793 | * 在不支持 ES2015 的旧版浏览器中,需要引入 polyfill 才能使用。 794 | 795 | [[↑] 回到顶部](#js-问题) 796 | 797 | ### 用转译成 JavaScript 的语言写 JavaScript 有什么优缺点? 798 | 799 | Some examples of languages that compile to JavaScript include CoffeeScript, Elm, ClojureScript, PureScript and TypeScript. 800 | 这些是转译成 JavaScript 的语言,包括 CoffeeScript、Elm、ClojureScript、PureScript 和 TypeScript。 801 | 802 | **优点:** 803 | 804 | * 修复了 JavaScript 中的一些长期问题,并摒弃了 JavaScript 不好的做法。 805 | * 在 JavaScript 的基础上提供一些语法糖,使我们能够编写更短的代码,我认为 ES5 缺乏语法糖的支持,但 ES2015 非常好。 806 | * 对于需要长时间维护的大型项目,静态类型非常好用(针对 TypeScript)。 807 | 808 | **缺点:** 809 | 810 | * 由于浏览器只运行 JavaScript,所以需要构建、编译过程,在将代码提供给浏览器之前,需要将代码转译为 JavaScript。 811 | * 如果 source map 不能很好地映射到预编译的源代码,调试会很痛苦。 812 | * 大多数开发人员不熟悉这些语言,需要学习它。如果将其用于项目,会增加团队成本。 813 | * 社区比较小(取决于语言),这意味着资源、教程、图书和工具难以找到。 814 | * 可能缺乏 IDE(编辑器)的支持。 815 | * 这些语言将始终落后于最新的 JavaScript 标准。 816 | * 开发人员应该清楚代码正在被编译到什么地方——因为这是实际运行的内容,是最重要的。 817 | 818 | 实际上,ES2015 已经大大改进了 JavaScript,编写体验很好。我现在还没有真正看到对 CoffeeScript 的需求。 819 | 820 | ###### 参考 821 | 822 | * https://softwareengineering.stackexchange.com/questions/72569/what-are-the-pros-and-cons-of-coffeescript 823 | 824 | [[↑] 回到顶部](#js-问题) 825 | 826 | ### 你使用什么工具和技巧调试 JavaScript 代码? 827 | 828 | * React 和 Redux 829 | * [React Devtools](https://github.com/facebook/react-devtools) 830 | * [Redux Devtools](https://github.com/gaearon/redux-devtools) 831 | * Vue 832 | * [Vue Devtools](https://github.com/vuejs/vue-devtools) 833 | * JavaScript 834 | * [Chrome Devtools](https://hackernoon.com/twelve-fancy-chrome-devtools-tips-dc1e39d10d9d) 835 | * `debugger`声明 836 | * 使用万金油`console.log`进行调试 837 | 838 | ###### 参考 839 | 840 | * https://hackernoon.com/twelve-fancy-chrome-devtools-tips-dc1e39d10d9d 841 | * https://raygun.com/blog/javascript-debugging/ 842 | 843 | [[↑] 回到顶部](#js-问题) 844 | 845 | ### 你使用什么语句遍历对象的属性和数组的元素? 846 | 847 | **对象:** 848 | 849 | * `for`循环:`for (var property in obj) { console.log(property); }`。但是,这还会遍历到它的继承属性,在使用之前,你需要加入`obj.hasOwnProperty(property)`检查。 850 | * `Object.keys()`:`Object.keys(obj).forEach(function (property) { ... })`。`Object.keys()`方法会返回一个由一个给定对象的自身可枚举属性组成的数组。 851 | * `Object.getOwnPropertyNames()`:`Object.getOwnPropertyNames(obj).forEach(function (property) { ... })`。`Object.getOwnPropertyNames()`方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值作为名称的属性)组成的数组。 852 | 853 | **数组:** 854 | 855 | * `for` loops:`for (var i = 0; i < arr.length; i++)`。这里的常见错误是`var`是函数作用域而不是块级作用域,大多数时候你想要迭代变量在块级作用域中。ES2015 引入了具有块级作用域的`let`,建议使用它。所以就变成了:`for (let i = 0; i < arr.length; i++)`。 856 | * `forEach`:`arr.forEach(function (el, index) { ... })`。这个语句结构有时会更精简,因为如果你所需要的只是数组元素,你不必使用`index`。还有`every`和`some`方法可以让你提前终止遍历。 857 | 858 | 大多数情况下,我更喜欢`.forEach`方法,但这取决于你想要做什么。`for`循环有更强的灵活性,比如使用`break`提前终止循环,或者递增步数大于一。 859 | 860 | [[↑] 回到顶部](#js-问题) 861 | 862 | ### 请解释可变对象和不可变对象之间的区别。 863 | 864 | * 什么是 JavaScript 中的不可变对象的例子? 865 | * 不变性有什么优点和缺点? 866 | * 你如何在自己的代码中实现不变性? 867 | 868 | **_可变对象_** 在创建之后是可以被改变的。 869 | 870 | **_不可变对象_** 在创建之后是不可以被改变的。 871 | 872 | 1. 在 `JavaScript` 中,`string` 和 `number` 从设计之初就是不可变(Immutable)。 873 | 2. **_不可变_** 其实是保持一个对象状态不变,这样做的好处是使得开发更加简单,可回溯,测试友好,减少了任何可能的副作用。但是,每当你想添加点东西到一个不可变(Immutable)对象里时,它一定是先拷贝已存在的值到新实例里,然后再给新实例添加内容,最后返回新实例。相比可变对象,这势必会有更多内存、计算量消耗。 874 | 3. 比如:构造一个纯函数 875 | 876 | ```js 877 | const student1 = { 878 | school: 'Baidu', 879 | name: 'HOU Ce', 880 | birthdate: '1995-12-15', 881 | }; 882 | 883 | const changeStudent = (student, newName, newBday) => { 884 | return { 885 | ...student, // 使用解构 886 | name: newName, // 覆盖name属性 887 | birthdate: newBday, // 覆盖birthdate属性 888 | }; 889 | }; 890 | 891 | const student2 = changeStudent(student1, 'YAN Haijing', '1990-11-10'); 892 | 893 | // both students will have the name properties 894 | console.log(student1, student2); 895 | // Object {school: "Baidu", name: "HOU Ce", birthdate: "1995-12-15"} 896 | // Object {school: "Baidu", name: "YAN Haijing", birthdate: "1990-11-10"} 897 | ``` 898 | 899 | ###### 参考 900 | 901 | * https://juejin.im/post/58d0ff6f1b69e6006b8fd4e9 902 | * https://www.interviewcake.com/concept/java/mutable 903 | * https://www.sitepoint.com/immutability-javascript/ 904 | 905 | [[↑] 回到顶部](#js-问题) 906 | 907 | ### 请解释同步和异步函数之间的区别。 908 | 909 | 同步函数阻塞,而异步函数不阻塞。在同步函数中,语句完成后,下一句才执行。在这种情况下,程序可以按照语句的顺序进行精确评估,如果其中一个语句需要很长时间,程序的执行会停滞很长时间。 910 | 911 | 异步函数通常接受回调作为参数,在调用异步函数后立即继续执行下一行。回调函数仅在异步操作完成且调用堆栈为空时调用。诸如从 Web 服务器加载数据或查询数据库等重负载操作应该异步完成,以便主线程可以继续执行其他操作,而不会出现一直阻塞,直到费时操作完成的情况(在浏览器中,界面会卡住)。 912 | 913 | [[↑] 回到顶部](#js-问题) 914 | 915 | ### 什么是事件循环?调用堆栈和任务队列之间有什么区别? 916 | 917 | 事件循环是一个单线程循环,用于监视调用堆栈并检查是否有工作即将在任务队列中完成。如果调用堆栈为空并且任务队列中有回调函数,则将回调函数出队并推送到调用堆栈中执行。 918 | 919 | 如果你没有看过 Philip Robert [关于事件循环的演讲](https://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html),你应该看一下。这是观看次数最多的 JavaScript 相关视频之一。 920 | 921 | ###### 参考 922 | 923 | * https://2014.jsconf.eu/speakers/philip-roberts-what-the-heck-is-the-event-loop-anyway.html 924 | * http://theproactiveprogrammer.com/javascript/the-javascript-event-loop-a-stack-and-a-queue/ 925 | 926 | [[↑] 回到顶部](#js-问题) 927 | 928 | ### 请解释`function foo() {}`和`var foo = function() {}`之间`foo`的用法上的区别。 929 | 930 | 前者是函数声明,后者是函数表达式。关键的区别在于函数声明会使函数体提升(具有与变量相同的提升行为),但函数表达式的函数体不能。有关变量提升的更多解释,请参阅上面关于变量提升的问题。如果你试图在定义函数表达式之前调用它,你会得到一个`Uncaught TypeError: XXX is not a function`的错误。 931 | 932 | **函数声明** 933 | 934 | ```js 935 | foo(); // 'FOOOOO' 936 | function foo() { 937 | console.log('FOOOOO'); 938 | } 939 | ``` 940 | 941 | **函数表达式** 942 | 943 | ```js 944 | foo(); // Uncaught TypeError: foo is not a function 945 | var foo = function() { 946 | console.log('FOOOOO'); 947 | }; 948 | ``` 949 | 950 | ###### 参考 951 | 952 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function 953 | 954 | [[↑] 回到顶部](#js-问题) 955 | 956 | ### 使用`let`、`var`和`const`创建变量有什么区别? 957 | 958 | 用`var`声明的变量的作用域是它当前的执行上下文,它可以是嵌套的函数,也可以是声明在任何函数外的变量。`let`和`const`是块级作用域,意味着它们只能在最近的一组花括号(function、if-else 代码块或 for 循环中)中访问。 959 | 960 | ```js 961 | function foo() { 962 | // 所有变量在函数中都可访问 963 | var bar = 'bar'; 964 | let baz = 'baz'; 965 | const qux = 'qux'; 966 | 967 | console.log(bar); // bar 968 | console.log(baz); // baz 969 | console.log(qux); // qux 970 | } 971 | 972 | console.log(bar); // ReferenceError: bar is not defined 973 | console.log(baz); // ReferenceError: baz is not defined 974 | console.log(qux); // ReferenceError: qux is not defined 975 | ``` 976 | 977 | ```js 978 | if (true) { 979 | var bar = 'bar'; 980 | let baz = 'baz'; 981 | const qux = 'qux'; 982 | } 983 | 984 | // 用 var 声明的变量在函数作用域上都可访问 985 | console.log(bar); // bar 986 | // let 和 const 定义的变量在它们被定义的语句块之外不可访问 987 | console.log(baz); // ReferenceError: baz is not defined 988 | console.log(qux); // ReferenceError: qux is not defined 989 | ``` 990 | 991 | `var`会使变量提升,这意味着变量可以在声明之前使用。`let`和`const`不会使变量提升,提前使用会报错。 992 | 993 | ```js 994 | console.log(foo); // undefined 995 | 996 | var foo = 'foo'; 997 | 998 | console.log(baz); // ReferenceError: can't access lexical declaration 'baz' before initialization 999 | 1000 | let baz = 'baz'; 1001 | 1002 | console.log(bar); // ReferenceError: can't access lexical declaration 'bar' before initialization 1003 | 1004 | const bar = 'bar'; 1005 | ``` 1006 | 1007 | 用`var`重复声明不会报错,但`let`和`const`会。 1008 | 1009 | ```js 1010 | var foo = 'foo'; 1011 | var foo = 'bar'; 1012 | console.log(foo); // "bar" 1013 | 1014 | let baz = 'baz'; 1015 | let baz = 'qux'; // Uncaught SyntaxError: Identifier 'baz' has already been declared 1016 | ``` 1017 | 1018 | `let`和`const`的区别在于:`let`允许多次赋值,而`const`只允许一次。 1019 | 1020 | ```js 1021 | // 这样不会报错。 1022 | let foo = 'foo'; 1023 | foo = 'bar'; 1024 | 1025 | // 这样会报错。 1026 | const baz = 'baz'; 1027 | baz = 'qux'; 1028 | ``` 1029 | 1030 | ###### 参考 1031 | 1032 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let 1033 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var 1034 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const 1035 | 1036 | [[↑] 回到顶部](#js-问题) 1037 | 1038 | ### ES6 的类和 ES5 的构造函数有什么区别? 1039 | 1040 | TODO 1041 | 1042 | [[↑] 回到顶部](#js-问题) 1043 | 1044 | ### 你能给出一个使用箭头函数的例子吗,箭头函数与其他函数有什么不同? 1045 | 1046 | TODO 1047 | 1048 | [[↑] 回到顶部](#js-问题) 1049 | 1050 | ### 在构造函数中使用箭头函数有什么好处? 1051 | 1052 | TODO 1053 | 1054 | [[↑] 回到顶部](#js-问题) 1055 | 1056 | ### 高阶函数(higher-order)的定义是什么? 1057 | 1058 | 高阶函数是将一个或多个函数作为参数的函数,它用于数据处理,也可能将函数作为返回结果。高阶函数是为了抽象一些重复执行的操作。一个典型的例子是`map`,它将一个数组和一个函数作为参数。`map`使用这个函数来转换数组中的每个元素,并返回一个包含转换后元素的新数组。JavaScript 中的其他常见示例是`forEach`、`filter`和`reduce`。高阶函数不仅需要操作数组的时候会用到,还有许多函数返回新函数的用例。`Function.prototype.bind`就是一个例子。 1059 | 1060 | **Map 示例:** 1061 | 1062 | 假设我们有一个由名字组成的数组,我们需要将每个字符转换为大写字母。 1063 | 1064 | ```js 1065 | const names = ['irish', 'daisy', 'anna']; 1066 | ``` 1067 | 1068 | 不使用高阶函数的方法是这样: 1069 | 1070 | ```js 1071 | const transformNamesToUppercase = function(names) { 1072 | const results = []; 1073 | for (let i = 0; i < names.length; i++) { 1074 | results.push(names[i].toUpperCase()); 1075 | } 1076 | return results; 1077 | }; 1078 | transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA'] 1079 | ``` 1080 | 1081 | 使用`.map(transformerFn)`使代码更简明 1082 | 1083 | ```js 1084 | const transformNamesToUppercase = function(names) { 1085 | return names.map(name => name.toUpperCase()); 1086 | }; 1087 | transformNamesToUppercase(names); // ['IRISH', 'DAISY', 'ANNA'] 1088 | ``` 1089 | 1090 | ###### 参考 1091 | 1092 | * https://medium.com/javascript-scene/higher-order-functions-composing-software-5365cf2cbe99 1093 | * https://hackernoon.com/effective-functional-javascript-first-class-and-higher-order-functions-713fde8df50a 1094 | * https://eloquentjavascript.net/05_higher_order.html 1095 | 1096 | [[↑] 回到顶部](#js-问题) 1097 | 1098 | ### 请给出一个解构(destructuring)对象或数组的例子。 1099 | 1100 | 解构是 ES6 中新功能,它提供了一种简洁方便的方法来提取对象或数组的值,并将它们放入不同的变量中。 1101 | 1102 | **数组解构** 1103 | 1104 | ```js 1105 | // 变量赋值 1106 | const foo = ['one', 'two', 'three']; 1107 | 1108 | const [one, two, three] = foo; 1109 | console.log(one); // "one" 1110 | console.log(two); // "two" 1111 | console.log(three); // "three" 1112 | ``` 1113 | 1114 | ```js 1115 | // 变量交换 1116 | let a = 1; 1117 | let b = 3; 1118 | 1119 | [a, b] = [b, a]; 1120 | console.log(a); // 3 1121 | console.log(b); // 1 1122 | ``` 1123 | 1124 | **对象解构** 1125 | 1126 | ```js 1127 | // 变量赋值 1128 | const o = { p: 42, q: true }; 1129 | const { p, q } = o; 1130 | 1131 | console.log(p); // 42 1132 | console.log(q); // true 1133 | ``` 1134 | 1135 | ###### 参考 1136 | 1137 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment 1138 | * https://ponyfoo.com/articles/es6-destructuring-in-depth 1139 | 1140 | [[↑] 回到顶部](#js-问题) 1141 | 1142 | ### ES6 的模板字符串为生成字符串提供了很大的灵活性,你可以举个例子吗? 1143 | 1144 | **_模板字面量_**(Template literals) 是允许嵌入表达式的字符串字面量。你可以使用多行字符串和字符串插值功能。 1145 | 1146 | **语法** 1147 | 1148 | ```js 1149 | `string text``string text line 1 1150 | string text line 2``string text ${expression} string text`; 1151 | 1152 | tag`string text ${expression} string text`; 1153 | ``` 1154 | 1155 | **示例** 1156 | 1157 | ```js 1158 | console.log(`string text line 1 1159 | string text line 2`); 1160 | // "string text line 1 1161 | // string text line 2" 1162 | 1163 | var a = 5; 1164 | var b = 10; 1165 | console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`); 1166 | // "Fifteen is 15 and 1167 | // not 20." 1168 | ``` 1169 | 1170 | ```js 1171 | //show函数采用rest参数的写法如下: 1172 | 1173 | let name = '张三', 1174 | age = 20, 1175 | message = show`我来给大家介绍:${name}的年龄是${age}.`; 1176 | 1177 | function show(stringArr, ...values) { 1178 | let output = ''; 1179 | 1180 | let index = 0; 1181 | 1182 | for (; index < values.length; index++) { 1183 | output += stringArr[index] + values[index]; 1184 | } 1185 | 1186 | output += stringArr[index]; 1187 | 1188 | return output; 1189 | } 1190 | 1191 | message; //"我来给大家介绍:张三的年龄是20." 1192 | ``` 1193 | 1194 | ###### 参考 1195 | 1196 | * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings 1197 | 1198 | [[↑] 回到顶部](#js-问题) 1199 | 1200 | ### 你能举出一个柯里化函数(curry function)的例子吗?它有哪些好处? 1201 | 1202 | 柯里化(currying)是一种模式,其中具有多个参数的函数被分解为多个函数,当被串联调用时,将一次一个地累积所有需要的参数。这种技术帮助编写函数式风格的代码,使代码更易读、紧凑。值得注意的是,对于需要被 curry 的函数,它需要从一个函数开始,然后分解成一系列函数,每个函数都需要一个参数。 1203 | 1204 | ```js 1205 | function curry(fn) { 1206 | if (fn.length === 0) { 1207 | return fn; 1208 | } 1209 | 1210 | function _curried(depth, args) { 1211 | return function(newArgument) { 1212 | if (depth - 1 === 0) { 1213 | return fn(...args, newArgument); 1214 | } 1215 | return _curried(depth - 1, [...args, newArgument]); 1216 | }; 1217 | } 1218 | 1219 | return _curried(fn.length, []); 1220 | } 1221 | 1222 | function add(a, b) { 1223 | return a + b; 1224 | } 1225 | 1226 | var curriedAdd = curry(add); 1227 | var addFive = curriedAdd(5); 1228 | 1229 | var result = [0, 1, 2, 3, 4, 5].map(addFive); // [5, 6, 7, 8, 9, 10] 1230 | ``` 1231 | 1232 | ###### 参考 1233 | 1234 | * https://hackernoon.com/currying-in-js-d9ddc64f162e 1235 | 1236 | [[↑] 回到顶部](#js-问题) 1237 | 1238 | ### 使用扩展运算符(spread)的好处是什么,它与使用剩余参数语句(rest)有什么区别? 1239 | 1240 | 在函数泛型编码时,ES6 的扩展运算符非常有用,因为我们可以轻松创建数组和对象的拷贝,而无需使用`Object.create`、`slice`或其他函数库。这个语言特性在 Redux 和 rx.js 的项目中经常用到。 1241 | 1242 | ```js 1243 | function putDookieInAnyArray(arr) { 1244 | return [...arr, 'dookie']; 1245 | } 1246 | 1247 | const result = putDookieInAnyArray(['I', 'really', "don't", 'like']); // ["I", "really", "don't", "like", "dookie"] 1248 | 1249 | const person = { 1250 | name: 'Todd', 1251 | age: 29, 1252 | }; 1253 | 1254 | const copyOfTodd = { ...person }; 1255 | ``` 1256 | 1257 | ES6 的剩余参数语句提供了一个简写,允许我们将不定数量的参数表示为一个数组。它就像是扩展运算符语法的反面,将数据收集到数组中,而不是解构数组。剩余参数语句在函数参数、数组和对象的解构赋值中有很大作用。 1258 | 1259 | ```js 1260 | function addFiveToABunchOfNumbers(...numbers) { 1261 | return numbers.map(x => x + 5); 1262 | } 1263 | 1264 | const result = addFiveToABunchOfNumbers(4, 5, 6, 7, 8, 9, 10); // [9, 10, 11, 12, 13, 14, 15] 1265 | 1266 | const [a, b, ...rest] = [1, 2, 3, 4]; // a: 1, b: 2, rest: [3, 4] 1267 | 1268 | const { e, f, ...others } = { 1269 | e: 1, 1270 | f: 2, 1271 | g: 3, 1272 | h: 4, 1273 | }; // e: 1, f: 2, others: { g: 3, h: 4 } 1274 | ``` 1275 | 1276 | ###### 参考 1277 | 1278 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax 1279 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters 1280 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment 1281 | 1282 | [[↑] 回到顶部](#js-问题) 1283 | 1284 | ### 如何在文件之间共用代码? 1285 | 1286 | 这取决于执行 JavaScript 的环境。 1287 | 1288 | 在客户端(浏览器环境)上,只要变量或函数在全局作用域(`window`)中声明,所有脚本都可以引用它们。或者,通过 RequireJS 采用异步模块定义(AMD)以获得更多模块化方法。 1289 | 1290 | 在服务器(Node.js)上,常用的方法是使用 CommonJS。每个文件都被视为一个模块,可以通过将它们附加到`module.exports`对象来导出变量和函数。 1291 | 1292 | ES2015 定义了一个模块语法,旨在替换 AMD 和 CommonJS。 这最终将在浏览器和 Node 环境中得到支持。 1293 | 1294 | [[↑] 回到顶部](#js-问题) 1295 | 1296 | ###### 参考 1297 | 1298 | * http://requirejs.org/docs/whyamd.html 1299 | * https://nodejs.org/docs/latest/api/modules.html 1300 | * http://2ality.com/2014/09/es6-modules-final.html 1301 | 1302 | ### 什么情况下会用到静态类成员? 1303 | 1304 | 静态类成员(属性或方法)不绑定到某个类的特定实例,不管哪个实例引用它,都具有相同的值。静态属性通常是配置变量,而静态方法通常是纯粹的实用函数,不依赖于实例的状态。 1305 | 1306 | ###### 参考 1307 | 1308 | * https://stackoverflow.com/questions/21155438/when-to-use-static-variables-methods-and-when-to-use-instance-variables-methods 1309 | 1310 | [[↑] 回到顶部](#js-问题) 1311 | 1312 | ### 其他答案 1313 | 1314 | * http://flowerszhong.github.io/2013/11/20/javascript-questions.html 1315 | 1316 | ### 请用原生js实现一个函数,给页面制定的任意一个元素添加一个透明遮罩(透明度可变,默认0.2),使这个区域点击无效,要求兼容IE8+及各主流浏览器,遮罩层效果如下图所示: 1317 | ![遮罩效果](/img/element-mask.jp) 1318 | 1319 | ``` 1320 | 1328 | 1329 |
1330 | 1331 | 1363 | ``` 1364 | 1365 | ### 请用代码写出(今天是星期x)其中x表示当天是星期几,如果当天是星期一,输出应该是"今天是星期一" 1366 | 1367 | ``` 1368 | var days = ['日','一','二','三','四','五','六']; 1369 | var date = new Date(); 1370 | 1371 | console.log('今天是星期' + days[date.getDay()]); 1372 | ``` 1373 | 1374 | ### 下面这段代码想要循环延时输出结果0 1 2 3 4,请问输出结果是否正确,如果不正确,请说明为什么,并修改循环内的代码使其输出正确结果 1375 | 1376 | ``` 1377 | for (var i = 0; i < 5; ++i) { 1378 | setTimeout(function () { 1379 | console.log(i + ' '); 1380 | }, 100); 1381 | } 1382 | ``` 1383 | 1384 | 不能输出正确结果,因为循环中setTimeout接受的参数函数通过闭包访问变量i。javascript运行环境为单线程,setTimeout注册的函数需要等待线程空闲才能执行,此时for循环已经结束,i值为5.五个定时输出都是5 1385 | 修改方法:将setTimeout放在函数立即调用表达式中,将i值作为参数传递给包裹函数,创建新闭包 1386 | 1387 | ``` 1388 | for (var i = 0; i < 5; ++i) { 1389 | (function (i) { 1390 | setTimeout(function () { 1391 | console.log(i + ' '); 1392 | }, 100); 1393 | }(i)); 1394 | } 1395 | ``` 1396 | 1397 | 1398 | 1399 | ### 现有一个Page类,其原型对象上有许多以post开头的方法(如postMsg);另有一拦截函数chekc,只返回ture或false.请设计一个函数,该函数应批量改造原Page的postXXX方法,在保留其原有功能的同时,为每个postXXX方法增加拦截验证功能,当chekc返回true时继续执行原postXXX方法,返回false时不再执行原postXXX方法 1400 | 1401 | ``` 1402 | function Page() {} 1403 | 1404 | Page.prototype = { 1405 | constructor: Page, 1406 | 1407 | postA: function (a) { 1408 | console.log('a:' + a); 1409 | }, 1410 | postB: function (b) { 1411 | console.log('b:' + b); 1412 | }, 1413 | postC: function (c) { 1414 | console.log('c:' + c); 1415 | }, 1416 | check: function () { 1417 | return Math.random() > 0.5; 1418 | } 1419 | } 1420 | 1421 | function checkfy(obj) { 1422 | for (var key in obj) { 1423 | if (key.indexOf('post') === 0 && typeof obj[key] === 'function') { 1424 | (function (key) { 1425 | var fn = obj[key]; 1426 | obj[key] = function () { 1427 | if (obj.check()) { 1428 | fn.apply(obj, arguments); 1429 | } 1430 | }; 1431 | }(key)); 1432 | } 1433 | } 1434 | } // end checkfy() 1435 | 1436 | checkfy(Page.prototype); 1437 | 1438 | var obj = new Page(); 1439 | 1440 | obj.postA('checkfy'); 1441 | obj.postB('checkfy'); 1442 | obj.postC('checkfy'); 1443 | ``` 1444 | 1445 | ### 完成下面的tool-tip 1446 | ![xxx](img/tip-box.jpg) 1447 | 1448 | ### 编写javascript深度克隆函数deepClone 1449 | 1450 | function deepClone(obj) { 1451 | var _toString = Object.prototype.toString; 1452 | 1453 | // null, undefined, non-object, function 1454 | if (!obj || typeof obj !== 'object') { 1455 | return obj; 1456 | } 1457 | 1458 | // DOM Node 1459 | if (obj.nodeType && 'cloneNode' in obj) { 1460 | return obj.cloneNode(true); 1461 | } 1462 | 1463 | // Date 1464 | if (_toString.call(obj) === '[object Date]') { 1465 | return new Date(obj.getTime()); 1466 | } 1467 | 1468 | // RegExp 1469 | if (_toString.call(obj) === '[object RegExp]') { 1470 | var flags = []; 1471 | if (obj.global) { flags.push('g'); } 1472 | if (obj.multiline) { flags.push('m'); } 1473 | if (obj.ignoreCase) { flags.push('i'); } 1474 | 1475 | return new RegExp(obj.source, flags.join('')); 1476 | } 1477 | 1478 | var result = Array.isArray(obj) ? [] : 1479 | obj.constructor ? new obj.constructor() : {}; 1480 | 1481 | for (var key in obj ) { 1482 | result[key] = deepClone(obj[key]); 1483 | } 1484 | 1485 | return result; 1486 | } 1487 | 1488 | function A() { 1489 | this.a = a; 1490 | } 1491 | 1492 | var a = { 1493 | name: 'qiu', 1494 | birth: new Date(), 1495 | pattern: /qiu/gim, 1496 | container: document.body, 1497 | hobbys: ['book', new Date(), /aaa/gim, 111] 1498 | }; 1499 | 1500 | var c = new A(); 1501 | var b = deepClone(c); 1502 | console.log(c.a === b.a); 1503 | console.log(c, b); 1504 | 1505 | ### 补充代码,鼠标单击Button1后将Button1移动到Button2的后面 1506 | 1507 | 1508 | 1509 | 1510 | TEst 1511 | 1512 | 1513 | 1514 |
1515 | 1516 | 1517 |
1518 | 1519 | 1543 | 1544 | 1545 | 1546 | ### 网页中实现一个计算当年还剩多少时间的倒数计时程序,要求网页上实时动态显示"××年还剩××天××时××分××秒" 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | TEst 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1602 | 1603 | 1604 | 1605 | 1606 | ### 完成一个函数,接受数组作为参数,数组元素为整数或者数组,数组元素包含整数或数组,函数返回扁平化后的数组 1607 | 如:[1, [2, [ [3, 4], 5], 6]] => [1, 2, 3, 4, 5, 6] 1608 | 1609 | ``` 1610 | var data = [1, [2, [ [3, 4], 5], 6]]; 1611 | 1612 | function flat(data, result) { 1613 | var i, d, len; 1614 | for (i = 0, len = data.length; i < len; ++i) { 1615 | d = data[i]; 1616 | if (typeof d === 'number') { 1617 | result.push(d); 1618 | } else { 1619 | flat(d, result); 1620 | } 1621 | } 1622 | } 1623 | 1624 | var result = []; 1625 | flat(data, result); 1626 | 1627 | console.log(result); 1628 | ``` 1629 | 1630 | ### 如何判断一个对象是否为数组 1631 | 如果浏览器支持Array.isArray()可以直接判断否则需进行必要判断 1632 | 1633 | ``` 1634 | /** 1635 | * 判断一个对象是否是数组,参数不是对象或者不是数组,返回false 1636 | * 1637 | * @param {Object} arg 需要测试是否为数组的对象 1638 | * @return {Boolean} 传入参数是数组返回true,否则返回false 1639 | */ 1640 | function isArray(arg) { 1641 | if (typeof arg === 'object') { 1642 | return Object.prototype.toString.call(arg) === '[object Array]'; 1643 | } 1644 | return false; 1645 | } 1646 | ``` 1647 | 1648 | ### 请评价以下事件监听器代码并给出改进意见 1649 | 1650 | ``` 1651 | if (window.addEventListener) { 1652 | var addListener = function (el, type, listener, useCapture) { 1653 | el.addEventListener(type, listener, useCapture); 1654 | }; 1655 | } 1656 | else if (document.all) { 1657 | addListener = function (el, type, listener) { 1658 | el.attachEvent('on' + type, function () { 1659 | listener.apply(el); 1660 | }); 1661 | }; 1662 | } 1663 | ``` 1664 | 1665 | 作用:浏览器功能检测实现跨浏览器DOM事件绑定 1666 | 1667 | 优点: 1668 | 1669 | 1. 测试代码只运行一次,根据浏览器确定绑定方法 1670 | 2. 通过``listener.apply(el)``解决IE下监听器this与标准不一致的地方 1671 | 3. 在浏览器不支持的情况下提供简单的功能,在标准浏览器中提供捕获功能 1672 | 1673 | 缺点: 1674 | 1675 | 1. document.all作为IE检测不可靠,应该使用if(el.attachEvent) 1676 | 2. addListener在不同浏览器下API不一样 1677 | 3. ``listener.apply``使this与标准一致但监听器无法移除 1678 | 4. 未解决IE下listener参数event。 target问题 1679 | 1680 | 改进: 1681 | 1682 | ``` 1683 | var addListener; 1684 | 1685 | if (window.addEventListener) { 1686 | addListener = function (el, type, listener, useCapture) { 1687 | el.addEventListener(type, listener, useCapture); 1688 | return listener; 1689 | }; 1690 | } 1691 | else if (window.attachEvent) { 1692 | addListener = function (el, type, listener) { 1693 | // 标准化this,event,target 1694 | var wrapper = function () { 1695 | var event = window.event; 1696 | event.target = event.srcElement; 1697 | listener.call(el, event); 1698 | }; 1699 | 1700 | el.attachEvent('on' + type, wrapper); 1701 | return wrapper; 1702 | // 返回wrapper。调用者可以保存,以后remove 1703 | }; 1704 | } 1705 | ``` 1706 | 1707 | ### 如何判断一个对象是否为函数 1708 | 1709 | ``` 1710 | /** 1711 | * 判断对象是否为函数,如果当前运行环境对可调用对象(如正则表达式) 1712 | * 的typeof返回'function',采用通用方法,否则采用优化方法 1713 | * 1714 | * @param {Any} arg 需要检测是否为函数的对象 1715 | * @return {boolean} 如果参数是函数,返回true,否则false 1716 | */ 1717 | function isFunction(arg) { 1718 | if (arg) { 1719 | if (typeof (/./) !== 'function') { 1720 | return typeof arg === 'function'; 1721 | } else { 1722 | return Object.prototype.toString.call(arg) === '[object Function]'; 1723 | } 1724 | } // end if 1725 | return false; 1726 | } 1727 | ``` 1728 | 1729 | ### 编写一个函数接受url中query string为参数,返回解析后的Object,query string使用application/x-www-form-urlencoded编码 1730 | 1731 | ``` 1732 | /** 1733 | * 解析query string转换为对象,一个key有多个值时生成数组 1734 | * 1735 | * @param {String} query 需要解析的query字符串,开头可以是?, 1736 | * 按照application/x-www-form-urlencoded编码 1737 | * @return {Object} 参数解析后的对象 1738 | */ 1739 | function parseQuery(query) { 1740 | var result = {}; 1741 | 1742 | // 如果不是字符串返回空对象 1743 | if (typeof query !== 'string') { 1744 | return result; 1745 | } 1746 | 1747 | // 去掉字符串开头可能带的? 1748 | if (query.charAt(0) === '?') { 1749 | query = query.substring(1); 1750 | } 1751 | 1752 | var pairs = query.split('&'); 1753 | var pair; 1754 | var key, value; 1755 | var i, len; 1756 | 1757 | for (i = 0, len = pairs.length; i < len; ++i) { 1758 | pair = pairs[i].split('='); 1759 | // application/x-www-form-urlencoded编码会将' '转换为+ 1760 | key = decodeURIComponent(pair[0]).replace(/\+/g, ' '); 1761 | value = decodeURIComponent(pair[1]).replace(/\+/g, ' '); 1762 | 1763 | // 如果是新key,直接添加 1764 | if (!(key in result)) { 1765 | result[key] = value; 1766 | } 1767 | // 如果key已经出现一次以上,直接向数组添加value 1768 | else if (isArray(result[key])) { 1769 | result[key].push(value); 1770 | } 1771 | // key第二次出现,将结果改为数组 1772 | else { 1773 | var arr = [result[key]]; 1774 | arr.push(value); 1775 | result[key] = arr; 1776 | } // end if-else 1777 | } // end for 1778 | 1779 | return result; 1780 | } 1781 | 1782 | function isArray(arg) { 1783 | if (arg && typeof arg === 'object') { 1784 | return Object.prototype.toString.call(arg) === '[object Array]'; 1785 | } 1786 | return false; 1787 | } 1788 | /** 1789 | console.log(parseQuery('sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8')); 1790 | */ 1791 | ``` 1792 | 1793 | ### 解析一个完整的url,返回Object包含域与window.location相同 1794 | 1795 | ``` 1796 | /** 1797 | * 解析一个url并生成window.location对象中包含的域 1798 | * location: 1799 | * { 1800 | * href: '包含完整的url', 1801 | * origin: '包含协议到pathname之前的内容', 1802 | * protocol: 'url使用的协议,包含末尾的:', 1803 | * username: '用户名', // 暂时不支持 1804 | * password: '密码', // 暂时不支持 1805 | * host: '完整主机名,包含:和端口', 1806 | * hostname: '主机名,不包含端口' 1807 | * port: '端口号', 1808 | * pathname: '服务器上访问资源的路径/开头', 1809 | * search: 'query string,?开头', 1810 | * hash: '#开头的fragment identifier' 1811 | * } 1812 | * 1813 | * @param {string} url 需要解析的url 1814 | * @return {Object} 包含url信息的对象 1815 | */ 1816 | function parseUrl(url) { 1817 | var result = {}; 1818 | var keys = ['href', 'origin', 'protocol', 'host', 1819 | 'hostname', 'port', 'pathname', 'search', 'hash']; 1820 | var i, len; 1821 | var regexp = /(([^:]+:)\/\/(([^:\/\?#]+)(:\d+)?))(\/[^?#]*)?(\?[^#]*)?(#.*)?/; 1822 | 1823 | var match = regexp.exec(url); 1824 | 1825 | if (match) { 1826 | for (i = keys.length - 1; i >= 0; --i) { 1827 | result[keys[i]] = match[i] ? match[i] : ''; 1828 | } 1829 | } 1830 | 1831 | return result; 1832 | } 1833 | ``` 1834 | 1835 | ### 完成函数getViewportSize返回指定窗口的视口尺寸 1836 | 1837 | ``` 1838 | /** 1839 | * 查询指定窗口的视口尺寸,如果不指定窗口,查询当前窗口尺寸 1840 | **/ 1841 | function getViewportSize(w) { 1842 | w = w || window; 1843 | 1844 | // IE9及标准浏览器中可使用此标准方法 1845 | if ('innerHeight' in w) { 1846 | return { 1847 | width: w.innerWidth, 1848 | height: w.innerHeight 1849 | }; 1850 | } 1851 | 1852 | var d = w.document; 1853 | // IE 8及以下浏览器在标准模式下 1854 | if (document.compatMode === 'CSS1Compat') { 1855 | return { 1856 | width: d.documentElement.clientWidth, 1857 | height: d.documentElement.clientHeight 1858 | }; 1859 | } 1860 | 1861 | // IE8及以下浏览器在怪癖模式下 1862 | return { 1863 | width: d.body.clientWidth, 1864 | height: d.body.clientHeight 1865 | }; 1866 | } 1867 | ``` 1868 | 1869 | ### 完成函数getScrollOffset返回窗口滚动条偏移量 1870 | 1871 | /** 1872 | * 获取指定window中滚动条的偏移量,如未指定则获取当前window 1873 | * 滚动条偏移量 1874 | * 1875 | * @param {window} w 需要获取滚动条偏移量的窗口 1876 | * @return {Object} obj.x为水平滚动条偏移量,obj.y为竖直滚动条偏移量 1877 | */ 1878 | function getScrollOffset(w) { 1879 | w = w || window; 1880 | // 如果是标准浏览器 1881 | if (w.pageXOffset != null) { 1882 | return { 1883 | x: w.pageXOffset, 1884 | y: w.pageYOffset 1885 | }; 1886 | } 1887 | 1888 | // 老版本IE,根据兼容性不同访问不同元素 1889 | var d = w.document; 1890 | if (d.compatMode === 'CSS1Compat') { 1891 | return { 1892 | x: d.documentElement.scrollLeft, 1893 | y: d.documentElement.scrollTop 1894 | } 1895 | } 1896 | 1897 | return { 1898 | x: d.body.scrollLeft, 1899 | y: d.body.scrollTop 1900 | }; 1901 | } 1902 | 1903 | 1904 | ### 现有一个字符串richText,是一段富文本,需要显示在页面上.有个要求,需要给其中只包含一个img元素的p标签增加一个叫pic的class.请编写代码实现.可以使用jQuery或KISSY. 1905 | 1906 | function richText(text) { 1907 | var div = document.createElement('div'); 1908 | div.innerHTML = text; 1909 | var p = div.getElementsByTagName('p'); 1910 | var i, len; 1911 | 1912 | for (i = 0, len = p.length; i < len; ++i) { 1913 | if (p[i].getElementsByTagName('img').length === 1) { 1914 | p[i].classList.add('pic'); 1915 | } 1916 | } 1917 | 1918 | return div.innerHTML; 1919 | } 1920 | 1921 | ### 请实现一个Event类,继承自此类的对象都会拥有两个方法on,off,once和trigger 1922 | 1923 | 1924 | function Event() { 1925 | if (!(this instanceof Event)) { 1926 | return new Event(); 1927 | } 1928 | this._callbacks = {}; 1929 | } 1930 | Event.prototype.on = function (type, handler) { 1931 | this_callbacks = this._callbacks || {}; 1932 | this._callbacks[type] = this.callbacks[type] || []; 1933 | this._callbacks[type].push(handler); 1934 | 1935 | return this; 1936 | }; 1937 | 1938 | Event.prototype.off = function (type, handler) { 1939 | var list = this._callbacks[type]; 1940 | 1941 | if (list) { 1942 | for (var i = list.length; i >= 0; --i) { 1943 | if (list[i] === handler) { 1944 | list.splice(i, 1); 1945 | } 1946 | } 1947 | } 1948 | 1949 | return this; 1950 | }; 1951 | 1952 | Event.prototype.trigger = function (type, data) { 1953 | var list = this._callbacks[type]; 1954 | 1955 | if (list) { 1956 | for (var i = 0, len = list.length; i < len; ++i) { 1957 | list[i].call(this, data); 1958 | } 1959 | } 1960 | }; 1961 | 1962 | Event.prototype.once = function (type, handler) { 1963 | var self = this; 1964 | 1965 | function wrapper() { 1966 | handler.apply(self, arguments); 1967 | self.off(type, wrapper); 1968 | } 1969 | this.on(type, wrapper); 1970 | return this; 1971 | }; 1972 | 1973 | ### 编写一个函数将列表子元素顺序反转 1974 | 1975 | ``` 1976 |
    1977 |
  • 1
  • 1978 |
  • 2
  • 1979 |
  • 3
  • 1980 |
  • 4
  • 1981 |
1982 | 1983 | 1993 | ``` 1994 | 1995 | ### 以下函数的作用是?空白区域应该填写什么 1996 | 1997 | ``` 1998 | // define 1999 | (function (window) { 2000 | function fn(str) { 2001 | this.str = str; 2002 | } 2003 | 2004 | fn.prototype.format = function () { 2005 | var arg = __1__; 2006 | return this.str.replace(__2__, function (a, b) { 2007 | return arg[b] || ''; 2008 | }); 2009 | }; 2010 | 2011 | window.fn = fn; 2012 | })(window); 2013 | 2014 | // use 2015 | (function () { 2016 | var t = new fn('

{1}{2}

'); 2017 | console.log(t.format('http://www.alibaba.com', 'Alibaba', 'Welcome')); 2018 | })(); 2019 | ``` 2020 | 2021 | define部分定义一个简单的模板类,使用{}作为转义标记,中间的数字表示替换目标,format实参用来替换模板内标记 2022 | 横线处填: 2023 | 2024 | 1. ``Array.prototype.slice.call(arguments, 0)`` 2025 | 2. ``/\{\s*(\d+)\s*\}/g`` 2026 | 2027 | ### 编写一个函数实现form的序列化(即将一个表单中的键值序列化为可提交的字符串) 2028 | 2029 | 2030 |
2031 | 2035 | 2040 | 2041 | 2042 | 2043 | 2044 | Football 2045 | Basketball 2046 | Female 2047 | Male 2048 |
2049 | 2050 | 2051 | 2120 | 2121 | ### 使用原生javascript给下面列表中的li节点绑定点击事件,点击时创建一个Object对象,兼容IE和标准浏览器 2122 | 2123 | ``` 2124 | 2130 | 2131 | Object: 2132 | { 2133 | "index": 1, 2134 | "name": "111", 2135 | "link": "http://1111" 2136 | } 2137 | ``` 2138 | 2139 | script: 2140 | 2141 | ``` 2142 | var EventUtil = { 2143 | getEvent: function (event) { 2144 | return event || window.event; 2145 | }, 2146 | getTarget: function (event) { 2147 | return event.target || event.srcElement; 2148 | }, 2149 | // 返回注册成功的监听器,IE中需要使用返回值来移除监听器 2150 | on: function (elem, type, handler) { 2151 | if (elem.addEventListener) { 2152 | elem.addEventListener(type, handler, false); 2153 | return handler; 2154 | } else if (elem.attachEvent) { 2155 | function wrapper(event) { 2156 | return handler.call(elem, event); 2157 | }; 2158 | elem.attachEvent('on' + type, wrapper); 2159 | return wrapper; 2160 | } 2161 | }, 2162 | off: function (elem, type, handler) { 2163 | if (elem.removeEventListener) { 2164 | elem.removeEventListener(type, handler, false); 2165 | } else if (elem.detachEvent) { 2166 | elem.detachEvent('on' + type, handler); 2167 | } 2168 | }, 2169 | preventDefault: function (event) { 2170 | if (event.preventDefault) { 2171 | event.preventDefault(); 2172 | } else if ('returnValue' in event) { 2173 | event.returnValue = false; 2174 | } 2175 | }, 2176 | stopPropagation: function (event) { 2177 | if (event.stopPropagation) { 2178 | event.stopPropagation(); 2179 | } else if ('cancelBubble' in event) { 2180 | event.cancelBubble = true; 2181 | } 2182 | } 2183 | }; 2184 | var DOMUtil = { 2185 | text: function (elem) { 2186 | if ('textContent' in elem) { 2187 | return elem.textContent; 2188 | } else if ('innerText' in elem) { 2189 | return elem.innerText; 2190 | } 2191 | }, 2192 | prop: function (elem, propName) { 2193 | return elem.getAttribute(propName); 2194 | } 2195 | }; 2196 | 2197 | var nav = document.getElementById('nav'); 2198 | 2199 | EventUtil.on(nav, 'click', function (event) { 2200 | var event = EventUtil.getEvent(event); 2201 | var target = EventUtil.getTarget(event); 2202 | 2203 | var children = this.children; 2204 | var i, len; 2205 | var anchor; 2206 | var obj = {}; 2207 | 2208 | for (i = 0, len = children.length; i < len; ++i) { 2209 | if (children[i] === target) { 2210 | obj.index = i + 1; 2211 | anchor = target.getElementsByTagName('a')[0]; 2212 | obj.name = DOMUtil.text(anchor); 2213 | obj.link = DOMUtil.prop(anchor, 'href'); 2214 | } 2215 | } 2216 | 2217 | alert('index: ' + obj.index + ' name: ' + obj.name + 2218 | ' link: ' + obj.link); 2219 | }); 2220 | ``` 2221 | 2222 | ### 有一个大数组,var a = ['1', '2', '3', ...];a的长度是100,内容填充随机整数的字符串.请先构造此数组a,然后设计一个算法将其内容去重 2223 | 2224 | ``` 2225 | /** 2226 | * 数组去重 2227 | **/ 2228 | function normalize(arr) { 2229 | if (arr && Array.isArray(arr)) { 2230 | var i, len, map = {}; 2231 | for (i = arr.length; i >= 0; --i) { 2232 | if (arr[i] in map) { 2233 | arr.splice(i, 1); 2234 | } else { 2235 | map[arr[i]] = true; 2236 | } 2237 | } 2238 | } 2239 | return arr; 2240 | } 2241 | 2242 | /** 2243 | * 用100个随机整数对应的字符串填充数组。 2244 | **/ 2245 | function fillArray(arr, start, end) { 2246 | start = start == undefined ? 1 : start; 2247 | end = end == undefined ? 100 : end; 2248 | 2249 | if (end <= start) { 2250 | end = start + 100; 2251 | } 2252 | 2253 | var width = end - start; 2254 | var i; 2255 | for (i = 100; i >= 1; --i) { 2256 | arr.push('' + (Math.floor(Math.random() * width) + start)); 2257 | } 2258 | return arr; 2259 | } 2260 | 2261 | var input = []; 2262 | fillArray(input, 1, 100); 2263 | input.sort(function (a, b) { 2264 | return a - b; 2265 | }); 2266 | console.log(input); 2267 | 2268 | normalize(input); 2269 | console.log(input); 2270 | ``` --------------------------------------------------------------------------------