seho 发布的文章
简书转载:JS的构造函数人人都能懂
大家都知道原型和原型链是 JavaScript 中最经典的问题之一,而构造函数又是原型和原型链的基础,所以先了解清楚构造函数以及它的执行过程可以更好地帮助我们学习原型和原型链的知识。
本文将从以下几个方面来探讨构造函数:
1.什么是构造函数
2.为什么要使用构造函数
3.构造函数的执行过程
4.构造函数的返回值
1.什么是构造函数
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。
2.为什么要使用构造函数
学习每一个概念,不仅要知道它是什么,还要知道为什么,以及解决什么样的问题。
举个例子,我们要录入一年级一班中每一位同学的个人信息,那么我们可以创建一些对象,比如:
var p1 = { name: 'zs', age: 6, gender: '男', hobby: 'basketball' };
var p2 = { name: 'ls', age: 6, gender: '女', hobby: 'dancing' };
var p3 = { name: 'ww', age: 6, gender: '女', hobby: 'singing' };
var p4 = { name: 'zl', age: 6, gender: '男', hobby: 'football' };
// ...
像上面这样,我们可以把每一位同学的信息当做一个对象来处理。但是,我们会发现,我们重复地写了很多无意义的代码。比如 name、age、gender、hobby 。如果这个班上有60个学生,我们得重复写60遍。
这个时候,构造函数的优势就体现出来了。我们发现,虽然每位同学都有 name、gender、hobby 这些属性, 但它们都是不同的,那我们就把这些属性当做构造函数的参数传递进去。而由于都是一年级的学生,age 基本都是6岁,所以我们就可以写死,遇到特殊情况再单独做处理即可。此时,我们就可以创建以下的函数:
function Person(name, gender, hobby) {
this.name = name;
this.gender = gender;
this.hobby = hobby;
this.age = 6;
}
当创建上面的函数以后, 我们就可以通过 new 关键字调用,也就是通过构造函数来创建对象了。
var p1 = new Person('zs', '男', 'basketball');
var p2 = new Person('ls', '女', 'dancing');
var p3 = new Person('ww', '女', 'singing');
var p4 = new Person('zl', '男', 'football');
// ...
此时你会发现,创建对象会变得非常方便。所以,虽然封装构造函数的过程会比较麻烦,但一旦封装成功,我们再创建对象就会变得非常轻松,这也是我们为什么要使用构造函数的原因。
在使用对象字面量创建一系列同一类型的对象时,这些对象可能具有一些相似的特征(属性)和行为(方法),此时会产生很多重复的代码,而使用构造函数就可以实现代码的复用。
3.构造函数的执行过程
先说一点基本概念。
function Animal(color) {
this.color = color;
}
当一个函数创建好以后,我们并不知道它是不是构造函数,即使像上面的例子一样,函数名为大写,我们也不能确定。只有当一个函数以 new 关键字来调用的时候,我们才能说它是一个构造函数。就像下面这样:
var dog = new Animal("black");
以下我们只讨论构造函数的执行过程,也就是以 new 关键字来调用的情况。
我们还是以上面的 Person 为例。
function Person(name, gender, hobby) {
this.name = name;
this.gender = gender;
this.hobby = hobby;
this.age = 6;
}
var p1 = new Person('zs', '男', 'basketball');
此时,构造函数会有以下几个执行过程:
(1) 当以 new 关键字调用时,会创建一个新的内存空间,标记为 Animal 的实例。
1 创建内存空间.png
(2) 函数体内部的 this 指向该内存
2 函数体内部的 this 指向该内存.png
通过以上两步,我们就可以得出这样的结论。
var p2 = new Person('ls', '女', 'dancing'); // 创建一个新的内存 #f2
var p3 = new Person('ww', '女', 'singing'); // 创建一个新的内存 #f3
每当创建一个实例的时候,就会创建一个新的内存空间(#f2, #f3),创建 #f2 的时候,函数体内部的 this 指向 #f2, 创建 #f3 的时候,函数体内部的 this 指向 #f3。
(3) 执行函数体内的代码
通过上面的讲解,你就可以知道,给 this 添加属性,就相当于给实例添加属性。
(4) 默认返回 this 。
由于函数体内部的 this 指向新创建的内存空间,默认返回 this ,就相当于默认返回了该内存空间,也就是上图中的 #f1。此时,#f1的内存空间被变量 p1 所接受。也就是说 p1 这个变量,保存的内存地址就是 #f1,同时被标记为 Person 的实例。
以上就是构造函数的整个执行过程。
4.构造函数的返回值
构造函数执行过程的最后一步是默认返回 this 。言外之意,构造函数的返回值还有其它情况。下面我们就来聊聊关于构造函数返回值的问题。
(1)没有手动添加返回值,默认返回 this 。
function Person1() {
this.name = 'zhangsan';
}
var p1 = new Person1();
按照上面讲的,我们复习一遍。首先,当用 new 关键字调用时,产生一个新的内存空间 #f11,并标记为 Person1 的实例;接着,函数体内部的 this 指向该内存空间 #f11;执行函数体内部的代码;由于函数体内部的 this 指向该内存空间,而该内存空间又被变量 p1 所接收,所以 p1 中就会有一个 name 属性,属性值为 'zhangsan'。
p1: {
name: 'zhangsan'
}
(2) 手动添加一个基本数据类型的返回值,最终还是返回 this。
function Person2() {
this.age = 28;
return 50;
}
var p2 = new Person2();
console.log(p2.age); // 28
p2: {
age: 28
}
如果上面是一个普通函数的调用,那么返回值就是 50。
(3) 手动添加一个复杂数据类型(对象)的返回值,最终返回该对象
直接上例子
function Person3() {
this.height = '180';
return ['a', 'b', 'c'];
}
var p3 = new Person3();
console.log(p3.height); // undefined
console.log(p3.length); // 3
console.log(p3[0]); // 'a'
再来一个例子
function Person4() {
this.gender = '男';
return { gender: '中性' };
}
var p4 = new Person4();
console.log(p4.gender); // '中性'
关于构造函数的返回值,无非就是以上几种情况,大家可以动手试一试,也就记住了。
最后总结一下,本文从四个方面介绍了构造函数,而构造函数是原型和原型链学习的基础,所以大家有必要花点时间好好学习一下关于构造函数的知识,下篇文章我会来讲讲人人都能看懂的原型链,敬请期待。
最后的最后,我所说的不一定都对,你一定要自己试试!
作者:李等等扣丁
链接:https://www.jianshu.com/p/95a5faee17f1
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
前端专栏:head标签中之你所不知道的事
head标签本身并不携带任何东西,他主要是作为盛放其他语义化的容器使用;
HTML规定了在html标签中head标签必须是第一个;且head标签中必须存在title标签作为网站的标题,最多只能包含一个base,如果文档有其他方式指定了title,比如ifrme框架,可以不指定title;
我们来讨论一下title,title是标题的意思,但是html中也有一个h1-h6 heading也是标题头部的意思,在中文来讲,它们非常的难以分辨,更别说老外了;
其实HTML研发的时候也讨论了这个问题,解决方案呢就是:title作为元信息标签可能会被用来分享卡片,收藏书签的作用,所以title起一个概括全文的作用,但是h1有上下文链接的作用,只是展示页面即使无法全写,也不会有太大影响
我们再来谈谈一个冷门标签base是HTML历史遗留的标签,base是提供了文档url的一个基准,在base中指定url,我们在全文档体重就可以不用写前缀url,但是这个标签非常的危险,容易和js冲突,所以不建议使用;
下面我们聊聊meta标签,最重中之重的标签,他是一组键值对,它是通用的元信息表示标签;
一般的meta是由name和content两个属性来定义,name表示元信息的名字,content表示元信息的值
表示页面所在的web-application的名字是IsForums;
html5引入了charset来设置编码;没有content和name
这个非常重要,所以我建议放在文档的第一个;
浏览器读HTML是ASCLL字符,众所周知ASCLL是UTF和大多数编码格式的子集;一般清空下,服务端会通过http头来指定正确的编码方式,但是有些特殊的情况事用file协议打开html,如果没http头,就得设置编码啦;
具有http-equiv属性的meta;
具有equiv的meta,表示执行一个命令,这样的meta不需要name属性;
name 为 viewport 的 meta
我们的content中的内容是键值对的方式,没有在html标准定义viewport,双方约定好就可以自由使用;
其他预定义的meta的name值:
文章梗概:head元信息容器,title文档标题,base页面基准url,meta元信息通用标签
在评论区找到了一批干货:推荐大家看一下
常见的还有
format-detection 禁止 iPhone 的自动识别-》
ps:关于name为viewport不是HTML规定,你找不到的,是行业规定,但是非常之重要;
Webpack4.0:最base的配置指南
webpack的版本为4
npm init -y
在安装之前我们需要安装node和npm,因为webpack是基于node创造的。
我们可以2种方式安装,一个是全局安装,一个是局部在项目安装。
我们如果选择了全局安装那么,我们就只能运行同一个版本的项目,但是如果是在项目中安装,我们就可以在电脑上运行多个不同版本的webpack
所以推荐第二种方式。
npm install webpack webpack-cli -D
安装成功之后,如果是全局安装是直接webpack index.js
webpack在最早是一个js编译器,但是随着发展,webpack不仅仅能够编译js,png,css等等都可以做到非常棒的打包;
所以webpack应该说是一个模块打包工具;
我们进入packge.json配置private为true,将script清空;
然后我们在根目录上建立index.js,再建立一个header,通过es导入模块的方式引入;
然后可以使用
npx webpack index.js
npx是node提供的一个命令,我们是局部安装,无法使用webpack index.js命令,所以用npx命令可以在本项目中webpack编译index.js
编译成功可以生成出来了一个dist文件夹,下面有一个main.js,这边就是我们打包之后,能够被浏览器阅读的js文件。
webpack团队为了丰富我们使用webpack的赶脚,所以提供了一系默认配置,包括我们在执行编译的时候,会自动生成dist和mainjs,这些都是提供的默认配置;
我们可以自己定义打包文件名称以及编译后的文件名和文件夹名字,需要我们重写webpack.config.js 这个文件名称我们不能改变
const path = require('path') // 引入nodejs函数
module.exports = {
entry: "./index.js",
output:{
filename: "bundle.js",
path: path.resolve(__dirname,'bundle') // 获取文件夹路径
}
}
我们用commonjs模块导出了一个对象,里面有编译的文件,和编译后的目录地址以及设置文件名称;
我们在这里之所以引入path函数,是因为不能写相对路径
我们配置好webpack之后,我们要去package中修改我们的script:
"scripts": {
"boundle":"webpack"
},
我们这边写这个代码的意思就是:我们可以用boundle关键字来取去找webpack在项目中,然后我们又定义了webpack配置:就可以轻松的使用如下命令来打包了:
npm run boundle
补充知识点:
前端专栏:三分钟搞定世界第一的css布局技巧
众所周知,css的世界,网页布局技术一直是占据着前端工程师几乎每天都会接触的东西;
从最早的,table布局,定位,浮动,margin,padding
到现在比较先进的flex
但是讲真,在flex之前,我们的布局技术感觉力不从心,flex问世之后布局的春天也慢慢来了,但是作为IT界,越晚来的技术一定是最牛逼的,这一点已经在很多框架和技术点上已经见证了,这个技术就是grid!
grid作为最先进的网格布局,上手非常快,也非常简单,但是还是有很多专门写css的前端程序员不知道grid,压根没听过,说明渗透率比flex低,所以今天这个文章,老沈保证三分钟看完所有常用知识点,就可以在项目中进行实战练习了。
第一分钟:
建立dom和初始化grid布局
<div class="container">
<div class="header">HEADER</div>
<div class="menu">MENU</div>
<div class="content">CONTENT</div>
<div class="footer">FOOTER</div>
</div>
.container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-gap: 5px;
}
首先,网格布局的容器:
1.声明display:grid
2.行 用repeat函数拆分成12列,每一列为1fr(份) 份的意思:除去确定尺寸,剩下将会自动平均分配,1fr就是一份
3.列 确定了3行,第一行的高是50,第二行是350px,第三行是50px
4.(可选)网格之间的间隙,还可传入2个参数,一个是列 / 行
第一分钟看完了?我们看看实际的效果。
第二分钟:
其次,为了把网格利用的非常好,我们需要来用div填格子;
1.在子div中我们可以通过grid-column-start 和 grid-column-end来规定开始和结束的网格线,ps:如果宽12列,那么加上最左边和最右边就是13条网格线(11+2,12列11条线),所以如果要沾满第一行,就必须是从1到13,可以用代码这样写:
grid-column-start:1
grid-column-end:13
为了简写我们可以grid-column:1/13
2.行是这样,列也是同理
第二分钟看完了?我们看看实际的效果
第三分钟
我们再来一种不一样的方式布局,如果数格子太low了,我们有没有更简单的方法,答案是有
我们可以利用
grid-template-areas:
"h h h h h h h h h h h h"
"m m c c c c c c c c c c"
"f f f f f f f f f f f f";
第一眼是不是没看懂?hhh mm cc ff是啥玩意啊,这个是自己定义,这个代码的意思就是说我在父元素定义了这个布局,我的子元素只要和这个hh mm进行一个标识匹配就可以不用数格子,那如何匹配呢?
.header {
grid-area: h;
}
天哪,这么秀的吗?不仅仅可以这么秀,如果你要空隙咋办?
grid-template-areas:
". h h h h h h h h h h ."
"m m c c c c c c c c c c"
"f f f f f f f f f f f f";
通过.的占位符就可以留出空隙了,我们可以结合媒体查询写一个非常简单的响应式布局;
@charset "utf-8";
.container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-gap: 5px;
/ 图表可视化表示 /
grid-template-areas:
"m m h h h h h h h h h h"
"m m c c c c c c c c c c"
"f f f f f f f f f f f f";
}
.header {
grid-area: h;
background: red;
}
.menu {
grid-area: m;
background: blue;
}
.content {
grid-area: c;
background: yellowgreen;
}
.footer {
grid-area: f;
background: black;
}
@media screen and (max-width: 640px){
.container {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 50px 350px 50px;
grid-gap: 5px;
/* 图表可视化表示 */
grid-template-areas:
"h h h h h h h h h h m m"
"c c c c c c c c c c c c"
"f f f f f f f f f f f f";
}
}
结束;转载请说明出处-因卓诶老沈