JS基础知识点(二)
== 与 ===
对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换,就会进行如下判断流程:
1.首先会判断两者类型是否相同,相同则会进行严格相等比较===
2.判断是否在对比null
和undefined
,是的话就会返回true
3.判断两者类型是否为string
和number
,是的话就会将字符串转换为number
4.判断两者类型是否有boolean
,有的话将boolean
转换为number
5.判断是否一方为object
,另一方为string
、number
、symbol
,是的话,将object
转换为原始类型再进行判断
思考题:
[] == ![]
, 为什么?
根据上面判断流程, ![]
为false
(上一节有涉及),然后进入4,转换为[] == 0
,然后进入5,转换为'' == 0
,进入3,转换为0 == 0
,成立。
更多对比,查看
深浅拷贝
浅拷贝
1.使用Object.assign
可以实现,它会拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址。
2.通过展开运算符...
来实现浅拷贝
深拷贝
一般可以通过JSON.parse(JSON.stringify(object))
来解决。
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
但是该方法有局限性的:
- 会忽略
undefined
- 会忽略
symbol
- 不能序列化函数
- 不能解决循环引用的对象
如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用MessageChannel
function structuralClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
}
var obj = {
a: 1,
b: {
c: 2
}
}
obj.b.d = obj.b
// 注意该方法是异步的
// 可以处理 undefined 和循环引用对象
const test = async () => {
const clone = await structuralClone(obj)
console.log(clone)
}
test()
也可以自己实现一个深拷贝,但是其实实现一个深拷贝是很困难的,需要我们考虑好多种边界情况,比如原型链如何处理、DOM 如何处理等等,下面实现的深拷贝只是简易版,更推荐使用lodash深拷贝
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非对象')
}
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj }
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
let obj = {
a: [1, 2, 3],
b: {
c: 2,
d: 3
}
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2
原型
函数对象都有prototype
, 任何一个对象都有原型,我们可以通过非标准属性__proto__
来访问一个对象的原型
// 纯对象的原型默认是个空对象
console.log({}.__proto__); // => {}
function Student(name, grade) {
this.name = name;
this.grade = grade;
}
const stu = new Student('xiaoMing', 6);
// Student 类型实例的原型,默认也是一个空对象
console.log(stu.__proto__); // => Student {}
理解几个名词:
constructor
: 构造器,我们也可以称之为类,我们可以通过new
构造器来构造一个实例。__proto__
: 一个访问器属性,非标准,暴露了通过它访问的对象的内部[[Prototype]]
(一个对象或null
),不过更推荐使用ES6
新增的Reflect.getPrototypeOf
或者Object.getPrototypeOf()
方法。prototype
: 原型对象,每个函数对象都有prototype
它们之间的关系如下图
原型链
当在一个对象
obj
上访问某个属性时,如果不存在于obj
,那么便会去对象的原型也就是obj.__proto__
上去找这个属性。如果有则返回这个属性,没有则去对象obj
的原型的原型也就是obj.__proto__.__proto__
去找,重复以上步骤。一直到访问纯对象的原型也就是Object.prototype
,没有的话续往上找也就是Object.prototype.__proto__
,其实就是null
,直接返回undefined
。
举个例子
function Student(name, grade) {
this.name = name;
this.grade = grade;
}
const stu = new Student();
console.log(stu.notExists); // => undefined
访问stu.notExists
的整个过程是:
1.先看stu
上是否存在notExists
,不存在,所以看stu.__proto__
stu.__proto__ === Student.prototype // => true
2.stu.__proto__
上也不存在notExists
属性,再看stu.__proto__.__proto__
,其实就是纯对象的原型:Object.prototype
console.log(stu.__proto__.__proto__ === {}.__proto__); // => true
3.纯对象的原型上也不存在notExists
属性,再往上,到stu.__proto__.__proto__.__proto__
上去找,其实就是null
console.log(new Object().__proto__.__proto__); // => null
4.null
不存在notExists
属性,返回undefined
各个原型之间构成的链,我们称之为原型链。
函数Student
的原型链:
思考题
function Page() {
return this.hosts;
}
Page.hosts = ['h1'];
Page.prototype.hosts = ['h2'];
const p1 = new Page();
const p2 = Page();
console.log(p1.hosts);
console.log(p2.hosts);
运行结果是:先输出undefiend
,然后报错TypeError: Cannot read property 'hosts' of undefined
。
为什么console.log(p1.hosts)
是输出undefiend
呢,因为new
的时候如果return
了对象,会直接拿这个对象作为new
的结果,因此,p1
应该是this.hosts
的结果,
而在new Page()
的时候,this
是一个以Page.prototype
为原型的target
对象,所以这里this.hosts
可以访问到Page.prototype.hosts
也就是['h2']
。
这样 p1 就是等于['h2']
,['h2']
没有hosts
属性所以返回undefined
。
为什么console.log(p2.hosts)
会报错呢,p2
是直接调用Page
构造函数的结果,直接调用page
函数,这个时候this
指向全局对象,全局对象并没hosts
属性,因此返回undefined
,往undefined
上访问hosts
当然报错。
JS基础知识点(二)的更多相关文章
- 进击Node.js基础(二)
一.一个牛逼闪闪的知识点Promise npm install bluebird 二.Promise实例 ball.html <!doctype> <!DOCTYPE html> ...
- js基础知识点收集
js基础知识点收集 js常用基本类型 function show(x) { console.log(typeof(x)); // undefined console.log(typeof(10)); ...
- js基础练习二之简易日历
今天学到了js基础教程3,昨天的课后练习还没来的及做,这个是类似简易日历的小案例,视频还没听完,今晚继续...... 先看效果图: 其实做过前面的Tab选项卡,这个就很好理解了,通过鼠标放在不同月份月 ...
- Three.js基础探寻二——正交投影照相机
本篇主要介绍照相机中的正交投影照相机. 第一篇传送门:Three.js基础探寻一 1.照相机 图形学中的照相机定义了三维空间到二维屏幕的投影方式. 针对投影方式照相机分为正交投影照相机和透视投影照相机 ...
- 记录21.07.23 —— Vue.js基础(二)
Vue基础(二) 过滤器 过滤器作用 全局过滤器 输出结果 私有过滤器 输出结果 把其中一个做点修改 错误信息 自定义指令 全局自定义指令 私有自定义指令 钩子函数 注意:fond-weight是粗细 ...
- 前端新人学习笔记-------html/css/js基础知识点(二)
4月7日学到的知识点: 一:<img src="1.png" alt="美女"/> alt是给图片添加介绍,当图片没加载出来时,会直接显示a ...
- 前端新人学习笔记-------html/css/js基础知识点
即将毕业的软件工程大学生一枚,秋季招聘应聘的是Android,今年来到公司实习,要求做前端开发,所以一切只有现学,现在根据视频来学习,然后开这个博客记录一下自己的学习过程,废话不多说,开写. 4月6日 ...
- Node.js基础学习二之POST请求
本篇介绍下 Node.js post 请求 需求: 用户登录,前端界面输入用户名和密码,点击登录请求后台验证,根据后台反馈的信息做出响应 前端: (1)使用form表单 (2)使用ajax异步请求 服 ...
- JS基础知识点(一)
原始类型 null undefined boolean number string symbol 注意 原始类型存储的都是值,是没有函数可以调用的,但实际上除null和undefined外,其他类型使 ...
随机推荐
- (二)Java编程基础
目录 一.关键字与保留字 二.标识符与变量 三.基本数据类型的转换 四.运算符 五.分支语句 五.循环语句 六.跳转语句 七.Java从键盘读取输入 一.关键字与保留字 定义:①关键字:Java关键字 ...
- 听说你的资源被盗用了,那你知道 Nginx 怎么防盗链吗?
上一篇文章讲了 Nginx 中的变量和运行原理,下面就来说一个主要提供变量并修改变量的值的模块,也就是我们要讲的防盗链模块:referer 模块. 简单有效的防盗链手段 场景 如果做过个人站点的同学, ...
- Spark文档阅读之二:Programming Guides - Quick Start
Quick Start: https://spark.apache.org/docs/latest/quick-start.html 在Spark 2.0之前,Spark的编程接口为RDD (Resi ...
- umi 调试
最近在umi. 设置一个layout字段, 结果左边菜单栏就出现了. 很神奇. 决定对这个库一探究竟. 我是一个喜欢看底层库的人,网上所有的启动方式都是yarn或者npm start 启动服务.然后 ...
- cb30a_c++_STL_算法_查找算法_(3)search_find_end
cb30a_c++_STL_算法_查找算法_(3)search_find_endsearch()pos = search(ideq.begin(), ideq.end(), ilist.begin() ...
- vc6.0的项目如何在整个项目中查询内容呢?试试vs2015
vc6.0的项目如何在整个项目中查询内容呢?试试vs2015 https://blog.csdn.net/txwtech/article/details/101308795
- 菜渣开源一个基于 EMIT 的 AOP 库(.NET Core)
目录 1,快速入门 1.1 继承 ActionAttribute 特性 1.2 标记代理类型 2,如何创建代理类型 2.1 通过API直接创建 2,创建代理类型 通过API 通过 Microsoft. ...
- mongoDB的基本使用方法
MongoDB 安装(乌班图系统) apt install mongodb mongoDB与sql的对比 SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数 ...
- Spring学习笔记下载
动力节点的spring视频教程相当的经典:下载地址 https://pan.baidu.com/s/1eTSOaae
- Mariadb之显式使用表锁和行级锁
首先我们来看看mariadb的锁定概念,所谓锁就是当一个进程或事务在操作某一资源时,为了防止其他用户或者进程或事务对其进行资源操作,导致资源抢占而发生冲突,通常在A进程操作该资源时,会对该资源进行加锁 ...