首页

为了设计更好的深色模式

分享达人

通过一些案例进行比较与实验,探索如何将UI深色模式设计的更好。

iOS作为UI/UE设计的风向标,一直是行业的引领者,不管你愿不愿意承不承认,他的每一次更新变化总能带动UI设计行业的一些大大小小的变革,并且产生更多的追随者,比如当年的iOS7开始的扁平化设计风格,对后续设计风格的影响直到现在已经7年了。



在最近半年,iOS在UI设计风格上最大的变革莫过于DarkMode(深色模式),在DarkMode之前,我们熟悉的UI界面往往都是浅白色界面为主,而从iOS13开始正式使用了DarkMode,界面突然可以变深色了,苹果官方说这样设计可以让眼睛更舒服的长时间阅读,为革命保护视力,而且更加省电增长续航,具体结果我们不得而知,需要科学家们去验证了,但是对于我们设计师来说带来的挑战就是要“黑白无常”了。



其实DarkMode从测试版算起已经差不多推出了有半年的时间了,一些知名的APP产品早已经有了自己的兼容方案,同时iOS原生界面也给了我们很多最佳实践案例,按道理大家对于DarkMode的设计方式方法应该已经掌握了差不多了,但直到这几天微信正式推出了自己的DarkMode兼容方案,才发现对DarkMode的探索还需要设计师们多多努力。谨以此文表达一下自己的观点,不妥之处敬请海涵。


从一个“列表页面”说起:

列表试图(TableView)是iOS中最常见的界面组件,一般常见于设置与栏目列表页面


iOS设置界面的浅色模式和深色模式看起来都非常协调。

下面我们看看微信发现页面,这个页面和iOS设置是很相似的。


如果单独看微信发现页面的浅色模式实际效果还是不错的。

但是直接转换到深色模式下就感觉突然差的很多了,甚至可以说是有点难看,这次微信真的做了一次黑天鹅?

 

到底是什么原因让微信发现页面在深色模式下视觉体验如此之差呢?

我们不妨将两个功能布局都相似的深色进行放在一起进行一下比较


组成色彩分析:

在色彩这块在这两个页面中微信和iOS基本保持一致,四层灰度设计能更好的保持页面整体干净整洁且层次分明,但是被A背景色上,微信的背景色选择了黑色偏绿的颜色,应该是微信设计师还是想体现出产品的标志色原色。

文字的颜色也较iOS略微深一点,但是在整体上影响并不大。


看来在主要色彩上并没有什么问题,那么为什么微信这个界面与iOS界面比起来视觉上要感觉差一些呢?

下面来看一下图标


图标设计分析:


图标上的差别主要在于线宽与外框,微信采用无外框统一线宽的线形图标,iOS采用的是有外框剪影图标。

我们我们把图标进行互换会怎么样呢?



观察到了吗?别看错了!

是的,我把故意位置做了对调,左边是iOS,右边是微信。替换图标后的微信明显加分不少,整个界面都整齐多了,而iOS换了图标后明显变得不够整齐了,潦草很多。


那么结论是微信的无框线性图标在深色模式下兼容有问题?是的的确如此。但是等一下,还有一些细节你注意到吗?换了图标的微信界面和之前的iOS界面比起来明显还是有点不够整齐,为什么呢?

来我们回过头来从细节再看一下iOS界面。


我们按照这个思路把刚才微信替换图标界面再排序一下!

界面视觉体验明显整齐了很多是不是!


疑问:

为什么细线图标和无框图标会在深色背景表现不够好,而在浅色背景下就没问题呢?

是不是所有的UI都会存在这样的问题呢?

我们再来看一些例子:


看来结论是一样的,线性图标在深色背景下的表现都是差强人意,反观带框图标适应性很强,浅色和深色模式下均能良好的适配,我来分析一下原因。


当年伽利略用望远镜往天上看,发现木星比金星大,换成肉眼看后金星则比木星大。他认为是眼睛的某种视觉特性造成了这种现象。

德国物理学家赫尔曼把这种错觉称为辐照错觉,就是说在黑暗背景下,亮度越高的物体看起来面积越大。


再来看一张图片


哪个圆圈看起来更大,显然是黑色背景下的白色圆形,实际上这只是一种错觉,所有圆圈是一样大。


光亮刺激会使得神经元产生非线性放大作用,导致刺激比实物本身看起来更大,白色圆形更亮,所以看起来更大一些。


线性图标是用线条勾画图案达到隐喻效果,一般线粗是2px~6px像素。



设计师在设计时候都是以最终视觉作为参考,而设计稿本身多是浅色背景,所以在浅色背景的映衬下图标视觉会显得稍大,视觉基本是平衡的,假如设计是4px而呈现出的效果其实是6px左右。


是不是觉得哪里有点不对了?按照这个逻辑黑色背景下白色线图标不应该是视觉更大、更明显吗?


我们还需要考虑一个因素,那就是色彩,之前的几个界面案例的线性图标都是彩色的,特别是黑色背景下,不同色彩的图标放在一起,会有明显的忽大忽小的感觉,会让界面感觉非常凌乱。


是不是感觉黄色最大,红色的最小?但是其实是一样的,这还是相同形状的,要是图标形状不同感受会更明显


看一个实际中的例子:

由于都是单色线性图标,在浅色和深色下表现还都不错的,但是单色图标略显界面单调,并不太建议这么设计。


毫无疑问,未来的UI场景需要适配多背景色风格,图标除了具备好看隐喻之外,更需要具备抗干扰性

带框图标是一个不错的解决方法,大胆预测带框图标会将成为未来一段时间图标设计主流!



结论

1:深色模式中灰度色阶在一个界面最多可分为四层。

2:为了适配深色模式,今后有框图标将会成为图标设计风格主流。

3:同样为了适配深色模式,细线图标将会被淘汰,剪影和粗线图标会流行起来。

4:图标除了个体设计上用心,在排列上也会极大影响到页面的整合视觉,光谱排列法是个不错的选择。



转自:站酷-

APP常见的8种导航模式

分享达人

合理的导航设计,会让用户轻松达到目的而又不会干扰和困扰用户的选择。



优秀的APP导航设计,能够合理地完美展示产品的功能,并快速引导用户使用,增强用户的识别度。合理的导航设计,会让用户轻松达到目的而又不会干扰和困扰用户的选择。 

网上对介绍导航文章已经有很多,有部分已过时,今天自己再重新整理一遍,方便自己也方便更多人理解。


为什么需要导航?
-
1、我可以去哪?
导航为了清晰指引用户完成任务。建立合理的导航系统,设计顺畅的任务路径,让用户不再像无头苍蝇一样,在各模块之间迷失。一个好的导航,能够扁平化用户的任务路径,减少用户操作成本,从而提高用户体验。 

2、我现在在哪?
用户当前位置要有清晰的标记,从哪里来,到哪里去。 



常见的8种导航形式
- 

标签式导航可分为 底部标签式 、舵式导航、Tab标签式导航。 

一、底部标签式导航
-
底部标签导航是目前最常见的导航形式。底部导航 一般采用3-4个标签,最多不会超过5个。
优点: 
1、入口直接清晰,操作路径短,便于在不同功能模块进行跳转 
2、直接展示入口内容,内容曝光度高 
缺点:
1、功能之间无主次 
2、扩展性差,不利于后期的功能扩展 


二、舵式导航
-
舵式导航是 底部导航的一种扩展形式,像轮船上用来指挥的船舵,两侧是其他操作按钮。 
普通标签导航难以满足导航的需求,就需要一些扩展形式,和标签导航相比,舵式导航 把核心功能放在中间,标签更加突出醒目,同时对主功能标签做了扩展功能。 

使用场景:
如1、产品需要特殊的引导,如58同城,引导用户发布任务。 

如2、社区产品引导用户发帖子

如3、凸显核心功能,如百度地图、高德等

优点: 
1、在默认加载的页面之外,又能够突出强调中间的入口 
2、入口直接清晰,操作路径短,便于不同功能模块进行跳转 
3、直接展示入口内容,内容曝光率高 
缺点:(与标签导航存在同样的弊端) 
1、功能之间无主次 
2、扩展性差,不利于后期的功能扩展 



三、Tab标签式导航
-
一般 用于二级导航,当内容分类较多的时,一般采用 顶部标签导航设计模式。 

使用场景:
如:为当前界面内不同模块的切换,或者查看不同的分类内容 
优点:
标签数量可以随意根据需求变化,可以左右滑动,衍生更多标签。 
缺点:
操作热区较小,有APP设计的交互前与后的样式差异不大,容易造成误操作的困惑。(不知道当前在哪个标签下) 


四、抽屉式导航
-
抽屉式导航的核心思路是“隐藏”。 隐藏非核心的操作与功能,让用户更专注于核心的功能操作上去, 一般用于二级菜单。  

优点: 
1、节省页面展示空间 
2、注意力聚焦在当前页面 
缺点:
1、左上角的按钮存在于单手操作热区难以触达; 
2、降低了用户对产品部分功能的参与度。 


五、宫格式导航
-
主要将入口全部集中在主页面中,各个 入口相互独立,没有太多的交集,无法跳转互通。 
采用这种导航的应用已经越来越少,往往用在二级页作为内容列表的一种图形化形式呈现,或是作为一系列工具入口的聚合。 

优点:
1、将入口进行聚合,入口也清晰直接 
2、操作路径较短,用户可以便捷的在不同的功能模块之间进行跳转 
3、扩展性好,方便增加多个入口 
缺点:
1、用户无法第一时间看到内容或者执行操作,选择的压力会比较大。 
2、返回路径较长,容易产生用户不良情绪。 


六、轮播式导航
-
采用Banner轮播导航,当应用信息足够扁平, 内容比较单薄时使用。特别是在产品初期,缺乏用户和内容,这种导航目前已经很少用。 
该方式就可以 凸显产品核心功能给予用户使用。(如:较早时腾讯极光APP、应用市场等) 

优点:

1、展示清晰直观,美观度高 
2、内容曝光度高,突出强调了展示内容 
3、交互动画可多样化 
缺点:
1、展示内容数量有限 


七、列表式导航
-
现有APP中一种主要的信息承载模式,列表导航和宫格导航类似,属于二级导航。 
列表式导航分为3类: 标题式列表、内容式列表、嵌入式列表。 
标题式列表:一般只显示一行文字,有的显示一行文字加一张图片等等。 
内容式列表:主要以内容为主,所以在列表中就会体现出部分内容信息,点击进去就是详情。 
嵌入式列表:嵌入式其实就是由多个列表层级组合而成的导航。 

优点:
1、结构清晰,易于理解; 
2、使用,能够帮助用户快速的定位去到对应的页面 
3、能够在列表上直接给出关于活动、更新的提示 
缺点:
1、排版方式单一 
2、多个入口之间不分级,没优先级之分 


八、组合式导航
-
多用于产品本身 功能较为复杂,既需要用户能 聚焦于内容,又需要给出用户不同页面之间的入口,以便用户进行直接跳转,那就采用组合式导航,利用不同导航的特性来满足产品需求。 
组合式导航目前最常见的导航方式。 
如: 标签式导航+列表式  ;标签式+宫格式  ; 舵式+列表式+标签式  等等; 

优点: 
1、组合式多样化 
2、能给出用户不同页面之间的入口,方便跳转 


总结
-
根据自己的产品功能和特性,采用不同导航模式。 

每个产品迭代发展和变化,也会导致产品导航在过程中不停的产生变化,就必须依据用户属性和使用场景进行调整。不拘泥任何模式,解决问题才是根本.




使用scss开发小程序(各种小程序平台通用)

seo达人

微信小程序的wxss、阿里旗下淘宝、支付宝小程序的acss等等语法很类似原生css,但是在web开发里用惯了动态css语言,再写回原生css很不习惯,尤其是父子样式的嵌套写法非常繁琐。

因此,我希望能有一个自动化构建方案,能够简单地将scss转换成小程序的样式语言。

方案1

以前写微信小程序的依赖库时用过,使用gulp编译,将源码和编译后的代码分别放到src和dist两个目录。gulp会处理src下面的所有文件,将其中的scss转换成css,并将其他所有文件原封不动挪到dist下相应位置。

这里就不详细说了,代码参考Wux

方案2

非常简单直接,使用Webstorm/IDEAFile Watchers功能实时转换。

安装Ruby和sass

确保命令行输入sass -v能出现版本号,安装过程略。

安装File Watchers

到插件市场上搜索并安装(已安装则跳过)

1.png

添加scss的转换脚本

现在安装完插件打开项目会自动弹出scss转css的向导,方便了很多。但还需要做一些修改,配置如下:

2.png

首先要将生成文件的后缀名改掉,比如这里我的淘宝小程序就得是acss

其次,将Arguments改为:

$FileName$:$FileNameWithoutExtension$.acss --no-cache --sourcemap=none --default-encoding utf-8 --style expanded

如果不加--no-cache,scss文件同目录下会出现一个.sass-cache目录。

如果不加--sourcemap=none, scss文件同目录下会出现一个.map文件。

如果不加--default-encoding utf-8, scss文件如果有中文注释转换就会报错。

style可不加,这里用的是无缩进和压缩的风格,反正小程序打包发布时还会压,这里保持可读性。

现在这个scss转换是单独作用于项目的,如果新建一个小程序项目,就需要重新添加(不建议设置成global,容易误伤)。

注意到File Watchers列表的右侧操作栏下方有导入导出按钮,可以将现在配好的设置导出保存,将来新建项目时只要导入一下就行了。


之后还有一个问题,如果我手动将编译后的css(即wxss或者acss,下略)文件删除,scss文件不改动的话,就不会重新编译出css文件。
或者万一监听失效或者不够及时,css还有可能是旧的。
所以还需要一个命令,用来将整个目录下的scss文件统一转换,确保没有遗漏和保持代码。

不过我看了半天sasssass-convert的文档,没有找到一个可用的写法,能让命令行遍历指定目录下的所有scss文件,将其转换成css放到源文件所在目录,并且将后缀名改为wxss或者acss

所以遍历这个行为只能交给nodejs来实现,代码如下:

创建编译脚本build/scss-convert.js

var path = require("path") var fs = require("fs") const { exec } = require('child_process') const basePath = path.resolve(__dirname, '../') function mapDir(dir, callback, finish) {
  fs.readdir(dir, function(err, files) { if (err) { console.error(err) return }
    files.forEach((filename, index) => { let pathname = path.join(dir, filename)
      fs.stat(pathname, (err, stats) => { // 读取文件信息 if (err) { console.log('获取文件stats失败') return } if (stats.isDirectory()) {
          mapDir(pathname, callback, finish)
        } else if (stats.isFile()) { if (!['.scss'].includes(path.extname(pathname))) { return }
          callback(pathname)
        }
      }) if (index === files.length - 1) {
        finish && finish()
      }
    })
  })
}

mapDir(
  basePath, function (file) { const newFileWithoutExt = path.basename(file, '.scss') if (newFileWithoutExt.startsWith('_')) { return // 按照scss规则,下划线开头的文件不会生成css } // exec可以让nodejs执行外部命令 exec(`sass --no-cache --sourcemap=none --default-encoding utf-8 --style expanded ${file}:${newFileWithoutExt}.acss`, { cwd: path.dirname(file) // 不写这个会导致生成的文件出现在根目录 }, (err, stdout, stderr) => { if (err) { console.log(err) return } console.log(`stdout: ${stdout}`)
    })
  }, function() { // console.log('xxx文件目录遍历完了') }
)

package.json里添加一条script:

 "scripts": { "scss": "node build/scss-convert",
  },

ES6数据的解构赋值使用及应用

前端达人


定义


ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)



本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

如果解构不成功,变量的值就等于undefined

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错、



解构赋值的用途:

交换变量的值

例如:let x=1,y=2;[x,y] = [y,x]



从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便



函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来



提取 JSON 数据,很多接口数据只需要其中某部分

例如aa.axios.get(res=>{let {data:result}=res;}),则res.data.result = result了



函数参数的默认值

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句



遍历 Map 结构

Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便



输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。* const { SourceMapConsumer, SourceNode } = require(“source-map”);


1、数组的解构赋值


左右两侧数据解构须得吻合,或者等号左边的模式,只匹配一部分的等号右边的数组(属于不完全解构)



特殊情况使用…扩展运算符,无值是空数组



左右两边等式的性质要相同,等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错,只要某种数据结构具有 Iterator



接口,都可以采用数组形式的解构赋值,例如Set结构



解构赋值允许指定默认值,当一个数组成员严格等于undefined,默认值才会生效,否则取赋值的值;如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值;默认值可以引用解构赋值的其他变量,但该变量必须已经声明



// 数组的解构赋值
 let [a,b] = [1,2];
 console.log([a,b],a);//[1, 2] 1
 let [aa] = [11,22];
 console.log(aa)//11
 let [aaa,bbb] = [111];
 console.log(aaa,bbb)//111 undefined
 let [head, ...tail] = [1, 2, 3, 4];
 console.log(head,tail)//1,[2,3,4]
 let [x, y, ...z] = ['a'];
 console.log(x,y,z)//a undefined []
 // 等号右边不是数组会报错
 // let [ab] = 121;
 // conosle.log(ab)//TypeError: 121 is not iterable
 // let [abc] = {}
 // conosle.log(abc)//TypeError: {} is not iterable
 // 默认值赋值
 let [zz = 1] = [undefined];
 console.log(zz)//1
 let [zzz = 1] = [null];
 console.log(zzz)//null
 let [foo = true] = [];
 console.log(foo)// true
 let [xxx, yyy = 'b'] = ['a'];
 console.log(xxx,yyy)//a,b
 let [xxxx, yyyy = 'b'] = ['a', undefined]; 
 console.log(xxxx,yyyy)//a,b
 function f() {
   console.log('aaa');
 }
 let [xx = f()] = [1];
 console.log(xx)//1
 let [qq=ww,ww=11] = [23,44];
 console.log(qq,ww)//23,44,因为ww申明比qq晚所以是undefined;

2、对象的解构赋值
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者

数组是按照位置区分,对象则是按照键名区分的,同样的解构失败则为undefine
可将已有方法对象解构赋值
嵌套赋值,注意是变量是否被赋值是模式还是键值
对象的解构赋值可以取到继承的属性
如果要将一个已经声明的变量用于解构赋值,必须非常小心
let xx; // {xx} = {xx: 1}这样会报错,

解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式
({} = [true, false]);//可执行

由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构

objFuc(){
            // 对象解构赋值
            let {b,a} = {a:1}
            console.log(a,b)//1 undefined
            // 已有对象解构赋值
            let { sin, cos } = Math;//将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上
            console.log(sin);//log() { [native code] }
            const { log } = console;
            log('hello') // hello
            // 
            let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
            console.log(baz);//aaa
            // 嵌套赋值
            let obj = {
              p: [
                'Hello',
                { y: 'World' }
              ]
            };
            let { p,p:[x, { y }] } = obj;
            console.log(x,y,p)//Hello World p: ['Hello',{ y: 'World' }]
            //继承赋值
            const obj1 = {};
            const obj2 = { foo: 'bar' };
            Object.setPrototypeOf(obj1, obj2);//obj1继承obj2
            const { foo } = obj1;
            console.log(foo) // "bar"
            // 默认值
            // 错误的写法
            let xx;
            // {xx} = {xx: 1};// SyntaxError: syntax error,Uncaught SyntaxError: Unexpected token '='
            ({xx} = {xx: 1});//正确写法
            console.log(xx)
            // 古怪的,等式左边可为空
            // ({} = [true, false]);
            // 对象可解构数组
            let arr = [1, 2, 3];
            let {0 : first, [arr.length - 1] : last} = arr;
            console.log(first,last)//1 3
        },


3、字符串的解构赋值

  • 字符串赋值
  • 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
strFuc(){
            // str:'yan_yan'
            let [a,b,c,d,e,f,g] = this.str;
            console.log(a,b,c,d,e,f,g)//y a n _ y a n
            // 对数组属性解构赋值
            let {length} = this.str;
            console.log(length)//7
        },

    

4、数值和布尔值的解构赋值

  • 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
  • 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错

let {toString: s} = 123;
console.log(s === Number.prototype.toString,s)//true ƒ toString() { [native code] }
let {toString: ss} = true;
console.log(ss === Boolean.prototype.toString,ss)// true ƒ toString() { [native code] }
// 右侧必须是数组或对象,undefined和null无法转为对象,所以对它们进行解构赋值,都会报错
// let { prop: x } = undefined; // TypeError
// let { prop: y } = null; // TypeError


    

5、函数参数的解构赋值

  • 也可使用默认值,注意默认值是指实参的默认值而不是形参的默认值
// 函数的解构赋值可使用默认值,注意默认值是指实参的默认值而不是形参的默认值
            function move({x=1, y=1}={}) {
              return [x, y];
            }
            function move1({x, y} = { x: 0, y: 0 }) {
              return [x, y];
            }
            function move2({x, y=1} = { x: 0, y: 0 }) {
              return [x, y];
            }
            console.log(move({x: 3, y: 8})); // [3, 8]
            console.log(move({x: 3})); // [3, 1]
            console.log(move({})); // [1, 1]
            console.log(move()); // [1,1]
            console.log(move1({x: 3, y: 8})); // [3, 8]
            console.log(move1({x: 3})); // [3, 1]
            console.log(move1({})); // [undefined, 1]
            console.log(move1()); // [0,0]
            console.log(move2({x: 3, y: 8})); // [3, 8]
            console.log(move2({x: 3})); // [3, 1]
            console.log(move2({})); // [undefined, 1]
            console.log(move2()); // [0,0]

6、圆括号问题
解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号怎么处理。ES6 的规则是,只要有可能导致解构的歧义,就不得使用圆括号。
可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号
总结:
不管是哪一类的解构赋值,等式右边的数据必须是对象形式(数组也是一种对象形式)
————————————————
版权声明:本文为CSDN博主「Yan_an_n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44258964/article/details/105643553

浅析HTTP协议

前端达人

目录

HTTP协议

HTTP请求:

HTTP响应:

会话与会话状态:

Cookie

Session

Cookie和Session的区别

HTTP协议


 HTTP请求:
Post /test.php HTTP/1.1                               //请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本

Host: www.test.com                                       //请求头

User-agent:mozilla/5.0(windows NT 6.1: rv: 15.0)

Gecko/20100101 firefox15.0

                                                                                    //空白行,代表请求头结束

Username=admin&passwd=admin                             //请求正文

HTTP请求方法



GET       请求获取Request-URI所标识的资源

POST     在Request-URI所标识的资源后附加新的数据

HEAD    请求获取由Request-URI所标识的资源的响应消息报头

PUT       请求服务器存储一个资源,并用Request-URI作为其标识

常用的为GET和POST;GET和POST的区别:

GET提交的内容会直接显示在URL中,私密性较差,可以用于显示一些公共资源;但是GET效率会比较高。

POST不会将内容显示在URL中,可以用于提交一些敏感数据,例如用户名或密码。

HTTP响应:
HTTP/1.1 200 OK                                         //响应行由协议版本号,响应状态码和文本描述组成

Data:sun,15 nov 2018 11:02:04  GMT    //响应头

Server:bfe/1.0.8.9

……

Connection: keep-alive

                                                                      //空白行,代表响应头结束

<html>

</html><title>index.heml</title>                  //响应正文

HTTP的状态码:

状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。

1xx:指示信息 —— 表示请求已接收,继续处理。

2xx:成功 —— 表示请求已被成功接收、理解、接受。

3xx:重定向 —— 要完成请求必须进行更进一步的操作。

4xx:客户端错误 —— 请求有语法错误或请求无法实现。

5xx:服务器端错误 —— 服务器未能实现合法的请求。

常见状态代码、状态描述的说明如下。

200 OK:客户端请求成功。

400 Bad Request:客户端请求有语法错误,不能被服务器所理解。

401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。

403 Forbidden:服务器收到请求,但是拒绝提供服务。

404 Not Found:请求资源不存在,举个例子:输入了错误的URL。

500 Internal Server Error:服务器发生不可预期的错误。

503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。

会话与会话状态:
       Web中的会话是指一个客户端浏览器与web服务器之间连续发生一系列请求和响应过程。会话状态是指在会话过程中产生的状态信息;借助会话状态,web服务器能够把属于同一会话中的一系列的请求和响应关联起来。

Cookie
概述

       Cookie是一种在客户端保持HTTP状态信息的技术,它好比商场发放的优惠卡。在浏览器访问Web服务器的某个资源时,由Web服务器在在HTTP响应头中附带传送给浏览器一片数据,web服务器传送给各个客户端浏览器的数据是可以各不相同的。

       一旦Web浏览器保存了某个Cookie,那么它在以后每次访问该Web服务器是都应在HTTP请求头中将这个Cookie回传个Web服务器。Web服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将CooKie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给Web服务器。

       一个Cookie只能标识一种信息,它至少含有一个标识该消息的名称(NAME)和和设置值(VALUE)。一个Web浏览器也可以存储多个Web站点提供的Cookie。浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

传送示意图



特点

存储于浏览器头部/传输与HTTP头部,写时带属性,读时无属性。由三元【name,domain,path】唯一确定Cookie。

Set-Cookie2响应头字段

Set-Cookie2头字段用于指定WEB服务器向客户端传送的Cookie内容,但是按照Netscape规范实现Cookie功能的WEB服务器, 使用的是Set-Cookie头字段,两者的语法和作用类似。Set-Cookie2头字段中设置的cookie内容是具有一定格式的字符串,它必须以Cookie的名称和设置值开头,格式为"名称=值”,后面可以加上0个或多个以分号(;) 和空格分隔的其它可选属性,属性格式一般为 "属性名=值”。

除了“名称=值”对必须位于最前面外,其他的可选属性可以任意。Cookie的名称只能由普通的英文ASCII字符组成,浏览器不用关心和理解Cookie的值部分的意义和格式,只要WEB服务器能理解值部分的意义就行。大多数现有的WEB服务器都是采用某种编码方式将值部分的内容编码成可打印的ASCII字符,RFC 2965规范中没有明确限定编码方式。

举例:   Set-Cookie2: user-hello; Version=1; Path=/

Cookie请求头字段

Cookie请求头字段中的每个Cookie之间用逗号(,)或分号(;)分隔。在Cookie请求字段中除了必须有“名称=值”的设置外,还可以有Version、path、domain、port等属性;在Version、path、domain、port等属性名之前,都要增加一个“$”字符作为前缀。Version属性只能出现一次,且要位于Cookie请求头字段设置值的最前面,如果需要设置某个Cookie信息的Path、Domain、Port等属性,它们必须位于该Cookie信息的“名称=值”设置之后。

       浏览器使用Cookie请求头字段将Cookie信息会送给Web服务器;多个Cookie信息通过一个Cookie请求头字段会送给Web服务器。

浏览器会根据下面几个规则决定是否发送某个Cookie信息:

       1、请求主机名是否与某个存储的Cookie的Domain属性匹配

       2、请求的端口号是否在该Cookie的Port属性列表中

       3、请求的资源路径是否在该Cookie的Path属性指定的目录及子目录中

       4、该Cookie的有效期是否已过

Path属性的指向子目录的Cookie排在Path属性指向父目录的Cookie之前

举例: Cookie: $Version=1; Course=Java; $Path=/hello/lesson;Course=vc; $Path=/hello

Cookie的安全属性

secure属性

当设置为true时,表示创建的Cookie会被以安全的形式向服务器传输,也就是只能在HTTPS连接中被浏览器传递到服务器端进行会话验证,如果是HTTP连接则不会传递该信息,所以不会被窃取到Cookie的具体内容。

 HttpOnly属性

如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。

总结:secure属性 是防止信息在传递的过程中被监听捕获后信息泄漏,HttpOnly属性的目的是防止程序获取cookie后进行攻击这两个属性并不能解决cookie在本机出现的信息泄漏的问题(FireFox的插件FireBug能直接看到cookie的相关信息)。

Session
使用Cookie和附加URL参数都可以将上一-次请求的状态信息传递到下一次请求中,但是如果传递的状态信息较多,将极大降低网络传输效率和增大服务器端程序处理的难度。

概述

Session技术是一种将会话状态保存在服务器端的技术,它可以比喻成是医院发放给病人的病历卡和医院为每个病人保留的病历档案的结合方式。客户端需要接收、记忆和回送Session的会话标识号,Session可以且通常是借助Cookie来传递会话标识号。



Session的跟踪机制

HttpSession对象是保持会话状态信息的存储结构,一个客户端在WEB服务器端对应一个各自的HttpSession对象。WEB服务器并不会在客户端开始访问它时就创建HttpSession对象,只有客户端访问某个能与客户端开启会话的服务端程序时,WEB应用程序才会创建一个与该客户端对应的HttpSession对象。WEB服务器为HttpSession对象分配一个独一无的会话标识号, 然后在响应消息中将这个会话标识号传递给客户端。客户端需要记住会话标识号,并在后续的每次访问请求中都把这个会话标识号传送给WEB服务器,WEB服务器端程序依据回传的会话标识号就知道这次请求是哪个客户端发出的,从而选择与之对应的HttpSession对象。

WEB应用程序创建了与某个客户端对应的HttpSession对象后,只要没有超出一个限定的空闲时间段,HttpSession对象就驻留在WEB服务器内存之中,该客户端此后访问任意的Servlet程序时,它们都使用与客户端对应的那个已存在的HttpSession对象。

Session是实现网上商城的购物车的最佳方案,存储在某个客户Session中的一个集合对象就可充当该客户的一个购物车。

超时管理

WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象。随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问如果某个客户端在一定的时间之 内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象变成垃圾。

如果客户端浏览器超时后再次发出访问请求,Web服务器则认为这是一个新的会话开始,将为之创建新的Httpsession对象和分配新的会话标识号。

利用Cookie实现Session的跟踪

如果WEB服务器处理某个访问请求时创建了新的HttpSession对象,它将把会话标识号作为一个Cookie项加入到响应消息中,通常情况下,浏览器在随后发出的访问请求中又将会话标识号以Cookie的形式回传给WEB服务器。WEB服务器端程序依据回传的会话标识号就知道以前已经为该客户端创建了HttpSession对象,不必再为该客户端创建新的HttpSession对象,而是直接使用与该会话标识号匹配的HttpSession对象,通过这种方式就实现了对同一个客户端的会话状态的跟踪。

利用URL重写实现Session跟踪

Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一 次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。 如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。

Cookie和Session的区别
session和cookies同样都是针对单独用户的变量(或者说是对象好像更合适点),不同的用户在访问网站的时候都会拥有各自的session或者cookies,不同用户之间互不干扰。

他们的不同点是:

1,存储位置不同

session在服务器端存储,比较安全,但是如果session较多则会影响性能

cookies在客户端存储,存在较大的安全隐患

2,生命周期不同

session生命周期在指定的时间(如20分钟) 到了之后会结束,不到指定的时间,也会随着浏览器进程的结束而结束。

cookies默认情况下也随着浏览器进程结束而结束,但如果手动指定时间,则不受浏览器进程结束的影响。

总结:简而言之,两者都是保存了用户操作的历史信息,但是存在的地方不同;而且session和cookie的目的相同,都是为了克服HTTP协议无状态的缺陷,但是完成方法不同。Session通过cookie在客户端保存session id,将用户的其他会话消息保存在服务端的session对象中;而cookie需要将所有信息都保存在客户端,因此存在着一定的安全隐患,例如本地Cookie中可能保存着用户名和密码,容易泄露。
————————————————
版权声明:本文为CSDN博主「悲观的乐观主义者」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43997530/article/details/105650267


浅显易懂的cookie的使用(设置和获取cookie缓存)

前端达人

js中cookie的使用(设置和获取cookie缓存)
生为一个已经入职一年多的前端小白,第一次写博客还有点小激动,有不足的地方还希望大家多多指出,因为最近项目有涉及到利用cookie缓存数据,所以在这边再巩固一下。

1、cookie的定义
在使用浏览器中,经常涉及到数据的交换,比如你登录系统账号,登录一个页面。我们经常会在此时设置记住账号啥的,或者自动登录选项。那这些都是怎么实现的呢,答案就是今天的主角cookie了,Cookie是由HTTP服务器设置的,保存在浏览器中,但HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。
从JavaScript的角度看,cookie 就是一些字符串信息。这些信息存放在客户端的计算机中,用于客户端计算机与服务器之间传递信息。
在JavaScript中可以通过 document.cookie 来读取或设置这些信息。由于 cookie 多用在客户端和服务端之间进行通信,所以除了JavaScript以外,服务端的语言(如PHP)也可以存取 cookie。

2、cookie的使用
设置cookie
function setCookie(c_name, value, expiredays) {
       var exdate = new Date()
       exdate.setDate(exdate.getDate() + expiredays)
       document.cookie = c_name + "=" + escape(value) +
           ((expiredays == null) ? "" : ";expires=" + exdate.toGMTString())+";path=/";
   }
1
2
3
4
5
6
调用该方法如:

var userId="123456";
setCookie("userId", userId, 30);
1
2
下面是里面参数的意义

参数 含义
c_name 自己定义的cookie名称
value 需要放在定义的c_name 中的值
expiredays cookie的有效期
这里有一个要注意点就是 " path=/"
" path=/"是只存下的cookie再该项目所有页面都能去获取,如果你想只存到弄个特定目录可以在path中指定路径,如:“path=/views/myHomePage”,z这样你可以在/views/myHomePage文件下所有页面都能取到你存的cookie了。

取回cookie
 function getCookie(c_name) {
        if (document.cookie.length > 0) {
            c_start = document.cookie.indexOf(c_name + "=")
            if (c_start != -1) {
                c_start = c_start + c_name.length + 1
                c_end = document.cookie.indexOf(";", c_start)
                if (c_end == -1) c_end = document.cookie.length
                return unescape(document.cookie.substring(c_start, c_end))
            }
        }
        return ""
    }
1
2
3
4
5
6
7
8
9
10
11
12
调用该方法如:

var newUserId= getCookie("userId");
console.log(newUserId)
alert(newUserId)
————————————————
版权声明:本文为CSDN博主「前端陈伟霆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43927397/article/details/105658614







如何分析产品设计语言?

雪涛

痛点

目前众多的网文产品中,设计同质化比较高,无论是产品视觉或是品牌运营视觉大多都缺乏独创性与统一性。番茄小说想要从众多产品中脱颖而出就需要走出一条合而不同的设计道路。因此提升产品的识别度与消费者对品牌的认知势在必行,设计需探索构建一套属于产品的语言体系。

解决方法

探索番茄小说的设计语言,建立产品认知

1. 文学特性——传统、网络的冷与热

传统文学

文学分为两类,严肃文学(看重语言和细节)、通俗文学(注重情节和故事,浅显易懂)。

周宪《文学理论导引》里定义「文学是以精致语言书写的具有艺术价值的以文本为中心的文化系统。」通过定义可以概括出文学的特点就是具有艺术价值,并且能够通过文字内容带人用户反思或者收获。当人们在阅读文学书籍时是冷静的,只有在这样的心境下读者才能更好的独立思考与分析。因此在氛围上需要给用户提供一个相对沉浸的空间、安逸的环境,通过分析可以提炼出的传统文学情绪关键词:沉浸、冷静、舒适、价值

网络文学

不同于传统文学,网络文学是顺应市场价值而诞生,是文学创作的平民化,让大家能够以网络为载体而发表的文字内容。广义来说,网络文学属于通俗文学的一类,注重情节和故事,通过文字传递的内容更加的朴实、接地气,在创作分类上也更加的多样化,作者可以天马行空的表达自己感受,可以说是在传统文学的基础上,给文字增加了几分烟火气息,也多了几分热闹的感受。

因此通过文学关键词可扩展出网络文学情绪关键词:沉浸、愉悦、烟火气

2. 调研分析

前期通过对小说用户群体与市场的走访调研,并通过数据分析,我们得到了如下结论:

产品用户类型

12-50岁青中年人;后GenX时代;一二三线城市有阅读小说习惯的人群;目前为对生活充满向往的学生与蓝领

产品品牌人格

乐观愉悦(轻松);品质(书好);亲民、丰富(书多)

产品视觉风格

品牌色贯穿产品,但不过分使用;视觉为产品功能服务,不做多余的设计;视觉表现多样化,但需要表达相同的产品气质;适度的留白,增强设计空间感

3. 小说产品特性

产品核心词:「沉浸中的愉悦」

正如我们对文学的分析,小说阅读同样是一种独立个体的行为方式,在读书时,我们不希望被人打扰,不希望被琐事细节阻断,我们希望在一个相对安静、舒适的环境下阅读,这是一种沉浸式的感受。

因此这里我们就根据用户的想要的感受,引入「沉浸」的概念——希望能够给读者留下一定的空间,并抛除繁杂打扰,让大家享受阅读与独立思考。其核心是围绕信息内容本身而呈现,设计不再作为独立于内容之外的元素存在,而将着眼于内容本身,为用户打造直观的视觉体验。拉大层级对比,增加适当的留白,在一定程度上增加少许修饰,打破绝对的冷淡。其既能体现出文学的特点,又能够在简约的基础上增加画面的构成感,给用户愉悦的感受。

触感

网络小说与传统文学另外一个最大的区别是触感。

传统文学大多以实体书籍纸张为承载,而网络文学来自于互联网是虚拟的。我们在阅读时,触摸纸张与书本朴实的质感,也能够给读者带来额外的舒适感受,因此如果能以视觉的形式还原用户对书籍的「触感」,不仅能够将网络与实体相链接,也可以帮助用户增加电子阅读的乐趣。

4. 建立番茄小说情绪版

根据归纳出的文学特征,以及调研用户年龄层与喜好,我们可以归纳出番茄小说基础原生关键词。

基础原生关键词

拓展衍生关键词

根据网络文学原生关键词,我们拓展出衍生词

  • 沉浸:安静、干净、整洁、内部、深色
  • 烟火气:城市、中国风、武侠、绘画、美女
  • 愉悦:跳跃、阳光、水果、温暖、火热
  • 触感:纸张、磨砂、纹理、褶皱、斑驳

图片搜索、提取情绪版

根据相关的衍生关键词,我们收集大量的视觉图片并将其汇总,借以分析其视觉特征

色彩提取

视觉映射

通过对情绪版的分析,我们可以得出结论并整理出番茄小说设计语言,轻量的色彩、写意式元素、非对称布局、纸纹理噪点

番茄小说设计语言

将传统的冷静沉浸与网络文学的热闹向融合是番茄小说设计语言的重要视觉呈现方式风格

多元化的简约设计+情感化修饰

  • 简洁:简约,做不饱和的设计,给用户空间感、想象的余地
  • 趣味:暖色+趣味,体现产品的温度与友好
  • 风格多样化:视觉多样化体现小说多样性、市井特点
  • 质感:增加视觉纹理,给用户带来真实阅读的感受

Logo

番茄的品牌名称基于「、优质」的产品理念,服务于产品设计、品牌设计中。番茄相对于红果是一个更加具象的表达,不仅可提高用户对产品的认知,也能传递小说品牌的理念和态度。基于此,这个理念框架是讲述品牌故事的关键载体。

logo动画展示

小说相关产品logo汇总

在logo的设计上我们将番茄的图形概念化,保留番茄籽,局部的留白让标志同样能表达空间与白的概念。我们选择在白色底上用红色非对称性式logo ,既区别了市面上大多产品logo样式,又能够加深用户对产品的印象,突出了「愉悦」的特性。

选定 logo 并设计图形+文字组合:

在文字设计上,相比正常宋体弱化文字衬线,为了突出空间感,我们扩大了字面拉伸了中宫的占比,这样做不仅提高文字识别度,整体气质也也能够与沉浸的定义相耦合。

品牌色

前期通过情绪版的分析,摘取关键词配色,综合归纳出符合番茄小说特性的的色彩搭配

通过对情绪版色彩的归纳,我们抽取具有代表性的颜色,作为番茄小说的品牌色

辅助图形

从logo中番茄图形的概念出发,提取出以圆、番茄籽、番茄轮廓为基本型的品牌图形元素

官方字体

考虑到官方字体在沉浸式页面中的运用,番茄官方字体的选择与品牌属性相契合的苹方体、宋体。

VI 呈现:

品牌视觉感受:

品牌体现—产品场景

番茄小说给人的感觉是安静、平和、友好。因此在颜色使用中以品牌色配合低饱和度背景色做搭配,突出产品的带给用户的沉浸、愉悦感。

运营场景—运营设计对品牌塑造的意义

第一眼的感受,往往决定了用户对产品的整体印象。目前在番茄小说的产品中,最直观的品牌视觉展示主要以书单活动banner为载体,其做为活动入口本身就处在一个前置的位置,占用空间大且更能吸引到用户的注意。因此,需要对运营焦点图设计精细化的打磨,让用户在打开产品的瞬间,快速塑造产品在用户心中的视觉形象。

番茄小说运营设计——和而不同

运营设计的基本原则

  • 信息快速传达
  • 促使用户行动

因此番茄小说的运营视觉需要紧密围绕在这个大前提下进行设计,快速传达信息=保证信息的简单化、文字有效性,促使用户行动=画面内容的趣味性、吸引性。

视觉呈现形式

遵循番茄体系,体现小说内核的「烟火」气质,视觉呈现多元化。以运营文案为中心,画面设计贴近内容,降低用户信息识别成本。

品牌运营视觉一期构建:手绘元素+非对称构图+质感

设计规范

运营视觉与品牌调性应是统一的,因此在运营设计的色彩选择需要与品牌配色相呼应,保证视觉与整个产品的和谐性。

运营插图案例

在运营活动中,依然要以产品所传递的气质来进行画面设计,即是保留沉浸的前提下,抽取关键词的某个方向来表达品牌运营所传递的理念。在色彩的使用上可以围绕关键词的方向来选择颜色,以表达内容所传递的信息,可适当使用品牌色作为点缀,但依然需要的保持视觉给人带来的平和感。

总结

作为一个从 0 到1的品牌,番茄小说的设计语言依然在不断的打磨、优化。整体清晰的品牌规划能够保证线上、线下、产品与营销的各个视觉设计环节更加统一,同时也为后续的设计指明方向,助力业务持续发展。

文章来源:优设    作者:今日头条UED

javascript中的this绑定

前端达人

his是一个关键字,表示执行当前函数的对象

  • this永远跟着当前函数走,
  • 永远是一个对象,

  • 永远在函数执行时才能确定。
  • 1. 默认绑定:没有明确被隶属对象执行的函数,this指向window


function fn(){
    console.log(this);              //window
    console.log(typeof this);       //object
}
fn();

- 严格模式下,this指向undefiend

"use strict";
function fn(){
    console.log(this);              //undefined
}
fn();




Webpack:知识点总结以及遇到问题的处理办法

前端达人

文章目录

0.官方文档:

1.webpack概述:

2.webpack的基本使用:

3.在项目中安装和配置 webpack:

4.配置自定义打包的自定义入口和出口:

4.配置自动打包功能:

5.配置生成预览页面功能:

6.配置自动打包相关参数:

7.webpack 中的加载器:

8.loader加载器的基本使用:

9.Vue单文件组件:

10.webpack 打包发布:

11.以上所有配置 webpack.config.js 截图


1.webpack概述:
webpack是一个流行的前端项目构建工具(打包工具) ,可以解决当前web开发中所面临的困境
webpack提供了友好的模块化支持,以及代码压缩混淆、处理js兼容问题、性能优化等强大的功能,从而让程序员把工作的重心放到具体的功能实现上,提高了开发效率和项目的可维护性

2.webpack的基本使用:
2.1:打开终端运行命令 npm init -y 初始化包管理配置文件 package.json

2.2:新建 src 源文件目录(里面放程序员自己写的代码比如 html css js images …)

2.3:如果需要引入 jquery 库 终端运行以下命令npm install jquery -S 安装 jquery

自己在src文件夹中创建 index.js 引入下载的jquery包import $ from 'jquery'

3.在项目中安装和配置 webpack:
3.1:终端运行 npm install webpack-cli -D 命令,安装webpack相关的包

这里要注意一个问题 : package.json 和 package-lock.json 文件里的名字默认为 “name”=“webpack”,在配置 webpack-cli 之前要把name 改成 其他名字 比如 “name”=“webpack_” 不然的话为出现无法安装的问题

具体可点击这里 Webpack依赖包安装问题解决方案
3.2:在项目根目录中 ,创建名为 webpack.config.js 的 webpack 配置文件

3.3:在 webpack.config.js 中,初始化一下基本配置

建议选择 development (打包速度快,体积大),项目上线是才改成 production (如果选择production会进行代码的压缩和混淆,打包速度慢,体积小)

3.4:在package.json中的 script节点 新增一个dev脚本 值为 webpack ,就可以实现打包功能



  • 在终端运行命令:npm run dev 就可以打包 默认打包成main.js在 dist文件夹中

  • src自己新建的index.html 中引入打包后的 js




属性描述符与Proxy的区别&Vue3.0为何改用Proxy

前端达人

属性描述符

什么是属性描述符?

属性描述符就是一个属性除了属性名与属性值之外的其他相关信息

通过Object.getOwnPropertyDescriptor(对象, 属性名)可以得到一个对象的某个属性的属性描述符

let obj = {
    a: 1
}
console.log(Object.getOwnPropertyDescriptor(obj, 'a'));
// {
//     value: 1,
//     writable: true,
//     enumerable: true,
//     configurable: true
// }

通过Object.getOwnPropertyDescriptors(对象)可以得到某个对象的所有属性描述符

let obj = {
    a: 1,
    b: 2
}
console.log(Object.getOwnPropertyDescriptors(obj));
// {
//     a: {
//         value: 1, 
//         writable: true,
//         enumerable: true,
//         configurable: true
//     }
//     b: {
//         value: 2, 
//         writable: true, 
//         enumerable: true, 
//         configurable: true
//     }
// }


接下来,说一说每一个属性描述符的作用

value-属性值

不多逼逼

configurable-属性描述符是否可被修改

当我们设置configurable为false以后,再去修改属性描述符的话,会报错


let obj = {
    a: 1,
    b: 2
}
Object.defineProperty(obj, 'a', {
    value: 'a',
    configurable: false
})
Object.defineProperty(obj, 'a', {
    value: 'a',
    configurable: true
})
// Uncaught TypeError: Cannot redefine property: a
//    at Function.defineProperty (<anonymous>)



enumerable-该属性是否可被枚举

当设置一个属性的enumerable为false时,该属性不可被forin循环
但是不影响forof循环,因为forof循环看有没有Symbol(Symbol.iterator)
forin循环的是属性名,forof循环的是属性值


日历

链接

个人资料

蓝蓝 http://www.lanlanwork.com

存档