person._proto_
指向Person.prototype
,也就是其对应的原型对象Person.prototype
是一个对象,可以把constructor
和_proto_
看作两个属性
Person.prototype.constructor
指向其构造函数PersonPerson.prototype._proto_
指向上一层的原型对象(Object.prototype)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvZFYvKA-1661951422560)(%E9%9D%A2%E8%AF%95%E5%87%86%E5%A4%87%2064d3ed4453ae44a38f71e8b99d75fcc4/Untitled%202.png)]
继承
Child.prototype = new Parent()
function A(){
this.name = 123;
}
A.prototype.getA = function(){
console.log(this);
}
let a= new A();
let funca = a.getA;
funca(); //这样就是window
a.funca(); //这样就是a
funca.call(a); //这样就是a
let
const
null
:
0
。Object.prototype.__proto__ === null
。undefined
:
undefined
。undefined
。undefined
。undefined
。undefined
。如何判断null
如何判断undefined
===
或不相等操作符!==
来决定一个变量是否拥有值,这里不使用标准相等操作符==
,是因为标准相等符还会会检查变量是不是为null,但是严格相等操作符不会检查。null不等同于undefined,这点我们会在后面讲到。console.log(data === void 0); //true
console.log(null == undefined); //true
安全获得undefined
void 0
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型;
基本数据类型
,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 类型,代表创建后独一无二且不可变的数据类型。是原始数据类型。复杂数据类型
:Object、Array、Function。是引用数据类型。栈(stack)
中的简单数据段, 占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。堆(heap)
中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。typeof a
a instanceof b
variable.constructor === Array
Object.prototype.toString.call(a)
result.slice(8, -1)
就能得到具体的类型。箭头函数是匿名函数,不能作为构造函数,不能使用new
箭头函数不绑定arguments,取而代之用rest参数…解决
箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值。箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply(),一旦确定了this指向就不再改变。
普通函数的this指向调用它的那个对象,例如obj.func,那么func中的this就是obj。在默认情况(非严格模式下,未使用‘use strict’),没有找到直接调用者,则this指的是window(约定俗成)。在严格模式下,没有直接调用者的函数中的this是underfined。使用call,apply,bind绑定的this指的是绑定对象。
在“准备工作”中完成了哪些工作:
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。
在普通函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。
普通函数的this指向调用它的那个对象,例如obj.func,那么func中的this就是obj。
普通函数中,嵌套函数中的 this 不会从外层函数中继承。
let 或者 const,变量是不会被绑定到 window 上的。
箭头函数的 this 指向函数定义时的 this,而非执行时。箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined。
一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。
但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
作用域在函数定义时就已经确定了。而不是在函数调用时确定。
取x的值时,就需要到另一个作用域中取,x就是自由变量。去哪取呢?要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记
call
apply
bind
Function.prototype.myCall = function(context = globalThis) {
// 设置 fn 为调用 myCall 的方法
context.fn = this;
// 获取剩余参数
const otherArg = Array.from(arguments).slice(1);
// 调用这个方法,将剩余参数传递进去
context.fn(otherArg);
// 将这个方法的执行结果传给 result
let result = context.fn();
// 删除这个变量
delete context.fn;
// 返回 result 结果
return result;
};
this.a = 1;
const fn = function() {
this.a = 2;
console.log(this.a);
}
fn.myCall(fn);
Function.prototype.myApply = function(context = globalThis, arr) {
// 设置 fn 为调用 myApply 的方法
context.fn = this;
let result;
// 如果存在参数,则传递进去
// 将结果返回给 result
if (arr) {
result = context.fn(arr);
} else { // 否则不传
result = context.fn();
}
// 删除这个变量
delete context.fn;
// 返回 result 结果
return result;
};
Function.prototype.myBind = function(context = globalThis) {
// 设置 fn 为调用 myBind 的方法
const fn = this;
// 获取该方法剩余参数
const otherArg = [...arguments].slice(1);
// 设置返回的一个新方法
const result = function() {
// 获取返回方法体的参数
const resultArg = [...arguments];
// 如果是通过 new 调用的,绑定 this 为实例对象
if (this instanceof result) {
fn.apply(this, otherArg.concat(resultArg));
} else { // 否则普通函数形式绑定 context
fn.apply(context, otherArg.concat(resultArg));
}
}
// 绑定原型链
result.prototype = Object.create(fn.prototype);
// 返回结果
return result;
};
this.a = 1;
const fn = function() {
this.a = 2;
console.log(this.a);
}
fn.myBind(fn);
fn();
防抖
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
如果在200ms内没有再次触发滚动事件,那么就执行函数
如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
节流
//防抖
window.onload = function() {
window.document.querySelector('#scroll-box').addEventListener('scroll', debounce(handle, 1000), true)
function handle() {
console.log("触发");
}
function debounce(fn, wait){
var timeout = null;
return function() {
if(timer !== null) {
// 若短时间内再触发,则清除定时器再开始一个新的
clearTimeout(timeout);
}
timeout = setTimeout(fn, wait);
}
}
}
//节流
function throttle(fn,delay){
var timer = null
var startTime = Date.now()
return function(){
var context = this//this是触发滚动的dom元素
var args = arguments
var curTime = Date.now()
var remaining = delay - (curTime - startTime)
clearTimeout(timer)
if(remaining <= 0){
// 这一次离上一次触发事件相距超过设定时间
fn.apply(context,args)
startTime = Date.now()
}else{
timer = setTimeout(fn, remaining)
}
}
}
for (var key in myObject) {
if(myObject.hasOwnProperty(key)){
console.log(key);
}
}
//或者是
Object.keys(myObject); //这样输出的是数组对象
application/x-www-form-urlencoded
multipart/form-data
application/json
text/xml
function myNew(func, ...args) {
// 1. 判断方法体
if (typeof func !== 'function') {
throw '第一个参数必须是方法体';
}
// 2. 创建新对象
const obj = {};
// 3. 这个对象的 __proto__ 指向 func 这个类的原型对象
// 即实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性
obj.__proto__ = Object.create(func.prototype);
// 为了兼容 IE 可以让步骤 2 和 步骤 3 合并
// const obj = Object.create(func.prototype);
// 4. 通过 apply 绑定 this 执行并且获取运行后的结果
let result = func.apply(obj, args);
// 5. 如果构造函数返回的结果是引用数据类型,则返回运行后的结果
// 否则返回新创建的 obj
const isObject = typeof result === 'object' && result !== null;
const isFunction = typeof result === 'function';
return isObject || isFunction ? result : obj;
}
// 测试
function Person(name) {
this.name = name;
return function() { // 用来测试第 5 点
console.log('返回引用数据类型');
};
}
// 用来测试第 2 点和第 3 点
Person.prototype.sayName = function() {
console.log(`My name is ${this.name}`);
}
const me = myNew(Person, 'jsliang'); // 用来测试第 4 点
me.sayName(); // My name is jsliang
console.log(me); // Person {name: 'jsliang'}
// 用来测试第 1 点
// const you = myNew({ name: 'jsliang' }, 'jsliang'); // 报错:第一个参数必须是方法体
Promise
对象是一个构造函数,用来生成 Promise
实例,所以 new Promise()
不足奇怪。new Promise()
传入一个函数,这个函数可以带 2 个参数:resolve
和 reject
。resolve
的作用是将 Promise
对象的状态从 “未完成” 变为 “成功”(pending -> resolved
)reject
的作用是将 Promise
对象的状态从 “未完成” 变为 “失败”(pending -> rejected
)resolve
和 reject
之前,它们还是 pending
的。.then
里可接受一个从resolve传进来的参数,.catch
里可接受一个从reject传进来的参数。Promise
有 3 种状态:pending
、fulfilled
、rejected
pending
fulfilled
(实际打印会看到 resolved
)rejected
如果你在 new Promise
中用了 resolve()
,那么它就会走 .then()
;
如果你用的是 reject()
,那么它就走 .catch()
。
all
const p = Promise.all([p1, p2, p3]);
p1
、p2
、p3
的状态都变成 fulfilled
,p
的状态才会变成 fulfilled
,此时 p1
、p2
、p3
的返回值组成一个数组,传递给 p
的回调函数。p1
、p2
、p3
之中有一个被 rejected
,p
的状态就变成 rejected
,此时第一个被 reject
的实例的返回值,会传递给 p
的回调函数。all和race的区别
.all()
作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。.race()
作用也是接收一组异步任务,然后并行执行异步任务,不管第一个执行完的结果是resolve还是reject,只保留取第一个执行完成的异步操作的结果。其他的方法仍在执行,不过执行结果会被抛弃。function add () {
const numberList = Array.from(arguments);
// 进一步收集剩余参数
const calculate = function() {
numberList.push(...arguments);
return calculate;
}
// 利用 toString 隐式转换,最后执行时进行转换
calculate.toString = function() {
return numberList.reduce((a, b) => a + b, 0);
}
return calculate;
}
// 实现一个 add 方法,使计算结果能够满足以下预期
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2, 3)(4)); // 10;
console.log(add(1)(2)(3)(4)(5)); // 15;
(1). 浏览器查询 DNS,获取域名对应的 IP 地址;
(2). 浏览器向服务器请求建立链接,发起TCP三次握手;
(3). 浏览器向服务器发送 HTTP 请求;
(4). 服务器做出响应;
(5). 浏览器解析并渲染页面。