new constructor[([arguments])]
参数如下:
-
constructor
一个指定对象实例的类型的类或函数。 -
arguments
一个用于被constructor
调用的参数列表。
2. 简单示例
举个简单示例:
function User (name){
this.name = name;
this.isAdmin = false;
}
const leo = new User(‘leo’);
console.log(leo.name, leo.isAdmin); // “leo” false
3. new 运算符操作过程
当一个函数被使用 new
运算符执行时,它按照以下步骤:
-
一个新的空对象被创建并分配给
this
。 -
函数体执行。通常它会修改
this
,为其添加新的属性。 -
返回
this
的值。
以前面 User
方法为例:
function User(name) {
// this = {};(隐式创建)
// 添加属性到 this
this.name = name;
this.isAdmin = false;
// return this;(隐式返回)
}
const leo = new User(‘leo’);
console.log(leo.name, leo.isAdmin); // “leo” false
当我们执行 new User('leo')
时,发生以下事情:
-
一个继承自
User.prototype
的新对象被创建; -
使用指定参数调用构造函数
User
,并将this
绑定到新创建的对象; -
由构造函数返回的对象就是
new
表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。
「需要注意」:
-
一般情况下,构造函数不返回值,但是开发者可以选择主动返回对象,来覆盖正常的对象创建步骤;
-
new User
等同于new User()
,只是没有指定参数列表,即User
不带参数的情况;
let user = new User; // <-- 没有参数
// 等同于
let user = new User();
- 任何函数都可以作为构造器,即都可以使用
new
运算符运行。
4. 构造函数中的方法
在构造函数中,也可以将方法绑定到 this
上:
function User (name){
this.name = name;
this.isAdmin = false;
this.sayHello = function(){
console.log("hello " + this.name);
}
}
const leo = new User(‘leo’);
console.log(leo.name, leo.isAdmin); // “leo” false
leo.sayHello(); // “hello leo”
六、可选链 “?.”
==========
详细介绍可以查看 《MDN 可选链操作符》 。
1. 背景介绍
在实际开发中,常常出现下面几种报错情况:
// 1. 对象中不存在指定属性
const leo = {};
console.log(leo.name.toString());
// Uncaught TypeError: Cannot read property ‘toString’ of undefined
// 2. 使用不存在的 DOM 节点属性
const dom = document.getElementById(“dom”).innerHTML;
// Uncaught TypeError: Cannot read property ‘innerHTML’ of null
在可选链 ?.
出现之前,我们会使用短路操作 &&
运算符来解决该问题:
const leo = {};
console.log(leo && leo.name && leo.name.toString()); // undefined
这种写法的缺点就是 「太麻烦了」 。
2. 可选链介绍
可选链 ?.
是一种 「访问嵌套对象属性的防错误方法」 。即使中间的属性不存在,也不会出现错误。如果可选链 ?.
前面部分是 undefined
或者 null
,它会停止运算并返回 undefined
。
语法:
obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
**「我们改造前面示例代码:」
// 1. 对象中不存在指定属性
const leo = {};
console.log(leo?.name?.toString());
// undefined
// 2. 使用不存在的 DOM 节点属性
const dom = document?.getElementById(“dom”)?.innerHTML;
// undefined
3. 使用注意
可选链虽然好用,但需要注意以下几点:
- 「不能过度使用可选链」;
我们应该只将 ?.
使用在一些属性或方法可以不存在的地方,以上面示例代码为例:
const leo = {};
console.log(leo.name?.toString());
这样写会更好,因为 leo
对象是必须存在,而 name
属性则可能不存在。
- 「可选链
?.
之前的变量必须已声明」;
在可选链 ?.
之前的变量必须使用 let/const/var
声明,否则会报错:
leo?.name;
// Uncaught ReferenceError: leo is not defined
- 「可选链不能用于赋值」 ;
let object = {};
object?.property = 1;
// Uncaught SyntaxError: Invalid left-hand side in assignment
- 「可选链访问数组元素的方法」 ;
let arrayItem = arr?.[42];
4. 其他情况:?.() 和 ?.[]
需要说明的是 ?.
是一个特殊的语法结构,而不是一个运算符,它还可以与其 ()
和 []
一起使用:
4.1 可选链与函数调用 ?.()
?.()
用于调用一个可能不存在的函数,比如:
let user1 = {
admin() {
alert(“I am admin”);
}
}
let user2 = {};
user1.admin?.(); // I am admin
user2.admin?.();
?.()
会检查它左边的部分:如果 admin 函数存在,那么就调用运行它(对于 user1
)。否则(对于 user2
)运算停止,没有错误。
4.2 可选链和表达式 ?.[]
?.[]
允许从一个可能不存在的对象上安全地读取属性。
let user1 = {
firstName: “John”
};
let user2 = null; // 假设,我们不能授权此用户
let key = “firstName”;
alert( user1?.[key] ); // John
alert( user2?.[key] ); // undefined
alert( user1?.[key]?.something?.not?.existing); // undefined
5. 可选链 ?.
语法总结
可选链 ?.
语法有三种形式:
-
obj?.prop
—— 如果obj
存在则返回obj.prop
,否则返回undefined
。 -
obj?.[prop]
—— 如果obj
存在则返回obj[prop]
,否则返回undefined
。 -
obj?.method()
—— 如果obj
存在则调用obj.method()
,否则返回undefined
。
正如我们所看到的,这些语法形式用起来都很简单直接。?.
检查左边部分是否为 null/undefined
,如果不是则继续运算。?.
链使我们能够安全地访问嵌套属性。
七、Symbol
========
规范规定,JavaScript 中对象的属性只能为 「字符串类型」 或者 「Symbol类型」 ,毕竟我们也只见过这两种类型。
1. 概念介绍
ES6引入Symbol
作为一种新的**「原始数据类型」,表示「独一无二」的值,主要是为了「防止属性名冲突」。ES6之后,JavaScript一共有其中数据类型:Symbol
、undefined
、null
、Boolean
、String
、Number
、Object
。「简单使用」**:
let leo = Symbol();
typeof leo; // “symbol”
Symbol 支持传入参数作为 Symbol 名,方便代码调试:**
let leo = Symbol(“leo”);
2. 注意事项**
Symbol
函数不能用new
,会报错。
由于Symbol
是一个原始类型,不是对象,所以不能添加属性,它是类似于字符串的数据类型。
let leo = new Symbol()
// Uncaught TypeError: Symbol is not leo constructor
Symbol
都是不相等的,「即使参数相同」。
// 没有参数
let leo1 = Symbol();
let leo2 = Symbol();
leo1 === leo2; // false
// 有参数
let leo1 = Symbol(‘leo’);
let leo2 = Symbol(‘leo’);
leo1 === leo2; // false
Symbol
不能与其他类型的值计算,会报错。
let leo = Symbol(‘hello’);
leo + " world!"; // 报错
${leo} world!
; // 报错
Symbol
不能自动转换为字符串,只能显式转换。
let leo = Symbol(‘hello’);
alert(leo);
// Uncaught TypeError: Cannot convert a Symbol value to a string
String(leo); // “Symbol(hello)”
leo.toString(); // “Symbol(hello)”
Symbol
可以转换为布尔值,但不能转为数值:
let a1 = Symbol();
Boolean(a1);
!a1; // false
Number(a1); // TypeError
a1 + 1 ; // TypeError
Symbol
属性不参与for...in/of
循环。
let id = Symbol(“id”);
let user = {
name: “Leo”,
age: 30,
};
for (let key in user) console.log(key); // name, age (no symbols)
// 使用 Symbol 任务直接访问
console.log( "Direct: " + userid );
3. 字面量中使用 Symbol 作为属性名
在对象字面量中使用 Symbol
作为属性名时,需要使用 「方括号」 ( []
),如 [leo]: "leo"
。好处:防止同名属性,还有防止键被改写或覆盖。
let leo = Symbol();
// 写法1
let user = {};
userleo = ‘leo’;
// 写法2
let user = {
leo : ‘leo’
}
// 写法3
let user = {};
Object.defineProperty(user, leo, {value : ‘leo’ });
// 3种写法 结果相同
userleo; // ‘leo’
「需要注意」 :Symbol作为对象属性名时,不能用点运算符,并且必须放在方括号内。
let leo = Symbol();
let user = {};
// 不能用点运算
user.leo = ‘leo’;
userleo ; // undefined
user[‘leo’] ; // ‘leo’
// 必须放在方括号内
let user = {
leo : function (text){
console.log(text);
}
}
userleo; // ‘leo’
// 上面等价于 更简洁
let user = {
leo{
console.log(text);
}
}
「常常还用于创建一组常量,保证所有值不相等」:
let user = {};
user.list = {
AAA: Symbol(‘Leo’),
BBB: Symbol(‘Robin’),
CCC: Symbol(‘Pingan’)
}
4. 应用:消除魔术字符串
「魔术字符串」:指代码中多次出现,强耦合的字符串或数值,应该避免,而使用含义清晰的变量代替。
function fun(name){
if(name == ‘leo’) {
console.log(‘hello’);
}
}
fun(‘leo’); // ‘hello’ 为魔术字符串
常使用变量,消除魔术字符串:
let obj = {
name: ‘leo’
};
function fun(name){
if(name == obj.name){
console.log(‘hello’);
}
}
fun(obj.name); // ‘hello’
使用Symbol
消除强耦合,使得不需关系具体的值:
let obj = {
name: Symbol()
};
function fun (name){
if(name == obj.name){
console.log(‘hello’);
}
}
fun(obj.name); // ‘hello’
5. 属性名遍历
Symbol作为属性名遍历,不出现在for...in
、for...of
循环,也不被Object.keys()
、Object.getOwnPropertyNames()
、JSON.stringify()
返回。
let leo = Symbol(‘leo’), robin = Symbol(‘robin’);
let user = {
}
for(let k of Object.values(user)){console.log(k)}
// 无输出
let user = {};
let leo = Symbol(‘leo’);
Object.defineProperty(user, leo, {value: ‘hi’});
for(let k in user){
console.log(k); // 无输出
}
Object.getOwnPropertyNames(user); // []
Object.getOwnPropertySymbols(user); // [Symbol(leo)]
Object.getOwnPropertySymbols
方法返回一个数组,包含当前对象所有用做属性名的Symbol值。
let user = {};
let leo = Symbol(‘leo’);
let pingan = Symbol(‘pingan’);
userleo = ‘hi leo’;
user[pingan] = ‘hi pingan’;
let obj = Object.getOwnPropertySymbols(user);
obj; // [Symbol(leo), Symbol(pingan)]
另外可以使用Reflect.ownKeys
方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
let user = {
age : 2,
address : 3,
}
Reflect.ownKeys(user); // [‘age’, ‘address’,Symbol(‘leo’)]
由于Symbol值作为名称的属性不被常规方法遍历获取,因此常用于定义对象的一些非私有,且内部使用的方法。
6. Symbol.for()、Symbol.keyFor()
6.1 Symbol.for()
「用于重复使用一个Symbol值」,接收一个**「字符串」**作为参数,若存在用此参数作为名称的Symbol值,返回这个Symbol,否则新建并返回以这个参数为名称的Symbol值。
let leo = Symbol.for(‘leo’);
let pingan = Symbol.for(‘pingan’);
leo === pingan; // true
Symbol()
和 Symbol.for()
区别:
Symbol.for(‘leo’) === Symbol.for(‘leo’); // true
Symbol(‘leo’) === Symbol(‘leo’); // false
6.2 Symbol.keyFor()
「用于返回一个已使用的Symbol类型的key」:
let leo = Symbol.for(‘leo’);
Symbol.keyFor(leo); // ‘leo’
let leo = Symbol(‘leo’);
Symbol.keyFor(leo); // undefined
7. 内置的Symbol值
ES6提供11个内置的Symbol值,指向语言内部使用的方法:
7.1 Symbol.hasInstance
当其他对象使用instanceof
运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo
在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)
。
class P {
return a instanceof Array;
}
}
[1, 2, 3] instanceof new P(); // true
P是一个类,new P()会返回一个实例,该实例的Symbol.hasInstance
方法,会在进行instanceof
运算时自动调用,判断左侧的运算子是否为Array
的实例。
7.2 Symbol.isConcatSpreadable
值为布尔值,表示该对象用于Array.prototype.concat()
时,是否可以展开。
let a = [‘aa’,‘bb’];
[‘cc’,‘dd’].concat(a, ‘ee’);
// [‘cc’, ‘dd’, ‘aa’, ‘bb’, ‘ee’]
a[Symbol.isConcatSpreadable]; // undefined
let b = [‘aa’,‘bb’];
b[Symbol.isConcatSpreadable] = false;
[‘cc’,‘dd’].concat(b, ‘ee’);
// [‘cc’, ‘dd’,[ ‘aa’, ‘bb’], ‘ee’]
7.3 Symbol.species
指向一个构造函数,在创建衍生对象时会使用,使用时需要用get
取值器。
class P extends Array {
static get Symbol.species{
return this;
}
}
解决下面问题:
// 问题: b应该是 Array 的实例,实际上是 P 的实例
class P extends Array{}
let a = new P(1,2,3);
let b = a.map(x => x);
b instanceof Array; // true
b instanceof P; // true
// 解决: 通过使用 Symbol.species
class P extends Array {
static get Symbol.species { return Array; }
}
let a = new P();
let b = a.map(x => x);
b instanceof P; // false
b instanceof Array; // true
7.4 Symbol.match
当执行str.match(myObject)
,传入的属性存在时会调用,并返回该方法的返回值。
class P {
return ‘hello world’.indexOf(string);
}
}
‘h’.match(new P()); // 0
7.5 Symbol.replace
当该对象被String.prototype.replace
方法调用时,会返回该方法的返回值。
let a = {};
a[Symbol.replace] = (…s) => console.log(s);
‘Hello’.replace(a , ‘World’) // [“Hello”, “World”]
7.6 Symbol.hasInstance
当该对象被String.prototype.search
方法调用时,会返回该方法的返回值。
class P {
constructor(val) {
this.val = val;
}
return s.indexOf(this.val);
}
}
‘hileo’.search(new P(‘leo’)); // 2
7.7 Symbol.split
当该对象被String.prototype.split
方法调用时,会返回该方法的返回值。
// 重新定义了字符串对象的split方法的行为
class P {
constructor(val) {
this.val = val;
}
let i = s.indexOf(this.val);
if(i == -1) return s;
return [
s.substr(0, i),
s.substr(i + this.val.length)
]
}
}
‘helloworld’.split(new P(‘hello’)); // [“hello”, “”]
‘helloworld’.split(new P(‘world’)); // [“”, “world”]
‘helloworld’.split(new P(‘leo’)); // “helloworld”
7.8 Symbol.iterator
对象进行for...of
循环时,会调用Symbol.iterator
方法,返回该对象的默认遍历器。
class P {
let i = 0;
while(this[i] !== undefined ) {
yield this[i];
++i;
}
}
}
let a = new P();
a[0] = 1;
a[1] = 2;
for (let k of a){
console.log(k);
}
7.9.Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。调用时,需要接收一个字符串参数,表示当前运算模式,运算模式有:
-
Number : 此时需要转换成数值
-
String : 此时需要转换成字符串
-
Default : 此时可以转换成数值或字符串
let obj = {
switch (hint) {
case ‘number’:
return 123;
case ‘string’:
return ‘str’;
case ‘default’:
return ‘default’;
default:
throw new Error();
}
}
};
2 * obj // 246
3 + obj // ‘3default’
obj == ‘default’ // true
String(obj) // ‘str’
7.10 Symbol.toStringTag
在该对象上面调用Object.prototype.toString
方法时,如果这个属性存在,它的返回值会出现在toString
方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object
]或[object Array]
中object
后面的那个字符串。
// 例一
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
专业技能
一般来说,面试官会根据你的简历内容去提问,但是技术基础还有需要自己去准备分类,形成自己的知识体系的。简单列一下我自己遇到的一些题
-
HTML+CSS
-
JavaScript
-
前端框架
-
前端性能优化
-
前端监控
-
模块化+项目构建
-
代码管理
-
信息安全
-
网络协议
-
浏览器
-
算法与数据结构
-
团队管理
最近得空把之前遇到的面试题做了一个整理,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,还有网上刷到的,我都统一的整理了一下,希望对大家有用。
其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器等等
由于文章篇幅有限,仅展示部分内容
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
// 例一
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-VDxmseKs-1712319199439)]
[外链图片转存中…(img-HzgxNgMJ-1712319199440)]
[外链图片转存中…(img-QPUAgnx6-1712319199440)]
[外链图片转存中…(img-2DWXWcDj-1712319199440)]
[外链图片转存中…(img-Klfg6g8B-1712319199440)]
[外链图片转存中…(img-jm2n4XNq-1712319199441)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-hjw6R0D4-1712319199441)]
专业技能
一般来说,面试官会根据你的简历内容去提问,但是技术基础还有需要自己去准备分类,形成自己的知识体系的。简单列一下我自己遇到的一些题
-
HTML+CSS
-
JavaScript
-
前端框架
-
前端性能优化
-
前端监控
-
模块化+项目构建
-
代码管理
-
信息安全
-
网络协议
-
浏览器
-
算法与数据结构
-
团队管理
最近得空把之前遇到的面试题做了一个整理,包括我本人自己去面试遇到的,还有其他人员去面试遇到的,还有网上刷到的,我都统一的整理了一下,希望对大家有用。
其中包含HTML、CSS、JavaScript、服务端与网络、Vue、浏览器等等
由于文章篇幅有限,仅展示部分内容
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算