JS与CSS预处理

JavaScript

原型链

  • 对象person._proto_指向Person.prototype,也就是其对应的原型对象
  • Person.prototype是一个对象,可以把constructor_proto_看作两个属性
    • Person.prototype.constructor指向其构造函数Person
    • Person.prototype._proto_指向上一层的原型对象(Object.prototype)
  • 对象是函数创建的,而函数却又是一种对象
    对象是属性的集合,函数是一种对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvZFYvKA-1661951422560)(%E9%9D%A2%E8%AF%95%E5%87%86%E5%A4%87%2064d3ed4453ae44a38f71e8b99d75fcc4/Untitled%202.png)]

  • 几个的重要方法:
  1. Object.getPrototypeOf(对象实例),用于返回[[Prototype]]的值(即返回原型对象)。
  2. **对象实例.hasOwnProperty(**属性),用于检测一个属性是存在于实例中,还是存在于原型中,它是从Object中继承而来的,只在给定属性存在于对象实例中时,才返回true。
  3. Object.keys(对象),是ES5的方法,可以取得一个对象上的所有属性,注意如果传入的参数是对象实例,那么它只会取得实例的所有可枚举属性,如果传入的是原型对象,那么也只会取得所有可枚举原型属性。
  4. Object.defineProperty(),是ES5的方法,这个方法接收三个参数:属性所在的对象,属性的名字和一个描述符对象。其中描述符对象的属性必须是:configurable、enumerable、writable和value。这个方法是vue.js实现双向绑定的核心(也是vue为什么只兼容到IE9的重要原因)。
  • 继承

    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
  • 访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链

let var const的区别

let

  1. 不允许重复声明;
  2. 块级作用域(局部变量);
  3. 不存在变量提升;定义前输出会报错
  4. 不影响作用域链;

const

  1. 声明必须赋初始值;
  2. 标识符一般为大写(习惯);
  3. 不允许重复声明;
  4. 值不允许修改;
  5. 块级作用域(局部变量);

null和undefined的区别

  • null

    1. Number(null) 得到 0
    2. 作为函数的参数,表示该函数的参数不是对象。
    3. 作为对象原型链的终点。Object.prototype.__proto__ === null
  • undefined

    1. Number(undefined) 得到 undefined
    2. 变量被声明但是没有赋值,等于 undefined
    3. 调用函数时,对应的参数没有提供,也是 undefined
    4. 对象没有赋值,这个属性的值为 undefined
    5. 函数没有返回值,默认返回 undefined
  • 如何判断null

    1. 可以使用严格相等符=== 或不相等操作符 !==判断
  • 如何判断undefined

    1. 使用严格相等符===或不相等操作符!==来决定一个变量是否拥有值,这里不使用标准相等操作符==,是因为标准相等符还会会检查变量是不是为null,但是严格相等操作符不会检查。null不等同于undefined,这点我们会在后面讲到。
    2. 使用typeof操作符,这种方式我们在上面已经使用过了,对未定义的变量检测时只能使用这种方式,要不然会出现报错。
    3. 用void 0来代替undefined进行判断,因为void 0始终返回的都是原始值undefined。console.log(data === void 0); //true
  • console.log(null == undefined); //true

  • 安全获得undefined

    void 0

symbol

  • ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript 语言的第七种数据类型,是一种类似于字符串的数据类型;

    1. Symbol 的值是唯一的,用来解决命名冲突的问题;
    2. Symbol 值不能与其他数据进行运算;
    3. Symbol 定义的对象属性不能使用for…in循环遍历 ,但是可以使用Reflect.ownKeys 来获取对象的所有键名;

变量

  • js 一共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 类型,代表创建后独一无二且不可变的数据类型。是原始数据类型。
  • 复杂数据类型:Object、Array、Function。是引用数据类型。
  • 两种类型的区别是:存储位置不同
    • 原始数据类型直接存储在栈(stack)中的简单数据段, 占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储。
    • 引用数据类型存储在堆(heap) 中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

js怎么判断变量

  • typeof a
    • 对某个变量类型的检测,基本类型除了 null 之外,都能正常地显示为对应的类型。引用类型除了函数会显示为 function,其他都显示为 object。
    • 所有 不能正常显示的打印出来都是object(例如null、object、array等)
    • 能区分number、string、boolean、undefined、function
  • a instanceof b
    • instanceof主要用于检测某个构造函数的原型对象(b)在不在某个对象(a)的原型链上。
    • 就是原型链的查找过程。a沿着_proto_,b沿着prototype,若相等了则true。
    • 只能区分Array、Function
  • variable.constructor === Array
    • 除了 undefined 和 null,其他类型基本可以通过 constructor 判断。
    • 不过因为 constructor 的属性是可以被修改的,可能导致检测出的结果不正确。
  • Object.prototype.toString.call(a)
    • 可以检测上面提到的所有类型,只需将结果 result.slice(8, -1) 就能得到具体的类型。
    • 首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于”[object Array]“的字符串作为结果(看过ECMA标准的应该都知道,[[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。
    • 若参数不为 null 或 undefined,则将参数转为对象,转为对象后,取得该对象的[Symbol.toStringTag] 属性值(可能会遍历原型链)作为 tag,如无该属性,或该属性值不为字符串类型,则依下表取得 tag, 然后返回 "[object " + tag + “]” 形式的字符串。
    • 对于原始类型,转为对象的方法即装箱。

箭头函数和普通函数

  • 箭头函数是匿名函数,不能作为构造函数,不能使用new

    箭头函数不绑定arguments,取而代之用rest参数…解决

    箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值。箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply(),一旦确定了this指向就不再改变。

  • 普通函数的this指向调用它的那个对象,例如obj.func,那么func中的this就是obj。在默认情况(非严格模式下,未使用‘use strict’),没有找到直接调用者,则this指的是window(约定俗成)。在严格模式下,没有直接调用者的函数中的thisunderfined。使用callapply,bind绑定的this指的是绑定对象。

this指向

  • 在“准备工作”中完成了哪些工作:

    • 变量、函数表达式——变量声明,默认赋值为undefined;
    • this——赋值;
    • 函数声明——赋值;

    这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。

  • 在普通函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。

  • 普通函数的this指向调用它的那个对象,例如obj.func,那么func中的this就是obj。

  • 普通函数中,嵌套函数中的 this 不会从外层函数中继承。

  • let 或者 const,变量是不会被绑定到 window 上的。

  • 箭头函数的 this 指向函数定义时的 this,而非执行时。箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined。

作用域链

  • 一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。

    但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。

  • 作用域在函数定义时就已经确定了。而不是在函数调用时确定。

  • 取x的值时,就需要到另一个作用域中取,x就是自由变量。去哪取呢?要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,切记切记

call apply bind

call

  • 第一个参数是要改变指向的对象,之后的参数形式是 arg1, arg2… 的形式

apply

  • 基本同 call,不同点在于第二个参数是一个数组 [arg1, arg2…]

bind

  • 改变 this 作用域会返回一个新的函数,这个函数不会马上执行。
  • 返回值:一个原函数的拷贝,并拥有指定的 this 值和初始参数。

手写call apply bind

  • call
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);
  • apply
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;
};
  • bind
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();

闭包

  • 可以简单理解成在一个函数内部的函数,内部函数持有外部函数内变量的引用。
  • 闭包是指有权访问另一个函数作用域中变量的函数。广义上来说,所有的js函数都可以称为闭包,因为js函数在创建时保存了当前的词法环境。
  • 使用场景
    1. setTimeout
    2. 防抖节流

防抖和节流

  • 防抖

    • 在第一次触发事件时,不立即执行函数,而是给出一个期限值比如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 in 和for of的区别

  • for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值。
  • 使用for in会遍历数组所有的可枚举属性,包括原型。for of遍历的只是数组内的元素,而不包括数组的原型属性method和索引name。
  • 通常用for in来遍历对象的键名。如果不想遍历原型方法和属性的话,可以在循环内部判断一下,hasOwnPropery方法可以判断某属性是否是该对象的实例属性。同样也可以用Object.keys(myObject)方法获取对象的实例属性组成的数组,不包括原型方法和属性。
for (var key in myObject) {
  if(myObject.hasOwnProperty(key)){
    console.log(key);
  }
}
//或者是
Object.keys(myObject); //这样输出的是数组对象
  • for…of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合。但是**不能遍历普通对象,**因为没有迭代器对象。

常用的几种 Content-Type

  • application/x-www-form-urlencoded
    • 浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。
    • 该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。
  • multipart/form-data
    • 该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
    • body 里字段分多个部分,每部分以 –boundary 开始,然后是内容描述信息
  • application/json
    • 消息主体是序列化后的 JSON 字符串。
    • {“title”:“test”,“sub”:[1,2,3]}
  • text/xml
    • 用来提交 XML 格式的数据

模板字符串

  • ``使用反引号定义;
  • 字符串中可以出现换行符;
  • 可以使用 ${xxx} 形式引用变量;

执行new的过程

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基础

  1. Promise 对象是一个构造函数,用来生成 Promise 实例,所以 new Promise() 不足奇怪。
  2. new Promise() 传入一个函数,这个函数可以带 2 个参数:resolvereject
  3. resolve 的作用是将 Promise 对象的状态从 “未完成” 变为 “成功”(pending -> resolved
  4. reject 的作用是将 Promise 对象的状态从 “未完成” 变为 “失败”(pending -> rejected
  5. 在没有执行 resolvereject 之前,它们还是 pending 的。
  6. .then里可接受一个从resolve传进来的参数,.catch里可接受一个从reject传进来的参数。
  7. .then()和.catch()自身会返回一个状态为pending的promise。

Promise 有 3 种状态:pendingfulfilledrejected

  1. 初始状态:pending
  2. 成功状态:fulfilled(实际打印会看到 resolved
  3. 失败状态:rejected

如果你在 new Promise 中用了 resolve(),那么它就会走 .then()

如果你用的是 reject(),那么它就走 .catch()

all

const p = Promise.all([p1, p2, p3]);

  1. 只有 p1p2p3 的状态都变成 fulfilledp 的状态才会变成 fulfilled,此时 p1p2p3 的返回值组成一个数组,传递给 p 的回调函数。
  2. 只要 p1p2p3 之中有一个被 rejectedp 的状态就变成 rejected,此时第一个被 reject 的实例的返回值,会传递给 p的回调函数。

all和race的区别

  1. .all() 作用是接收一组异步任务,然后并行执行异步任务,并且在所有异步操作执行完后才执行回调。
  2. .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). 浏览器解析并渲染页面。

css预处理

  • CSS 预处理器定义了一种专门的编程语言,为 CSS 增加了 一些编程的特性,将 CSS 作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。通俗的说,CSS 预处理器用一种专门 的编程语言,进行 Web 页面样式设计,然后再编译成正常的 CSS 文件。
  • 预处理器例如:LESS、Sass、Stylus,用来预编译 Sass 或 less css sprite,增强了 css 代码的复 用性,还有层级、mixin、 变量、循环、函数等,具有很方便的 UI 组件模块化开发能力,极大的提高工作效率。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值