js日常记录

一、数组中对象去重
// 数组中对象去重
let newAgency = []
agencyCodeArr = agencyCodeArr.reduce((cur,next)=>{
    newAgency[next.agencyCode] ? "" : newAgency[next.agencyCode] = true && cur.push(next)
    return cur
},[])//设置cur默认类型为数组,并且初始值为空的数组
二、判断对象长度
let obj = {a:1,b:undefined}
Object.values(obj.length)   // 2
三、判断对象中是否含有某个属性
let obj = {a:1,b:undefined}
obj.hasOwnProperty(isCustomize)  // false
obj.hasOwnProperty(a)  // true
三、使用scrollIntoView()方法导致整个页面上移问题

方法1:
使用scrollIntoView({block: "end", inline: "nearest"})元素的底部将与可滚动祖先的可见区域的底部对齐

document.querySelector('.tree').scrollIntoView({block: "end", inline: "nearest"});

说明:

element.scrollIntoView(alignToTop); //布尔参数
alignToTop
true:元素的顶部将对齐到可滚动祖先的可见区域的顶部。对应于scrollIntoViewOptions: {block: "start", inline: "nearest"}。(默认值)
false:元素的底部将与可滚动祖先的可见区域的底部对齐。对应于scrollIntoViewOptions: {block: "end", inline: "nearest"}

注:element.scrollIntoView() 相当于 element.scrollIntoView(true)
参考文章:详细介绍scrollIntoView()方法属性

方法2:在页面最外层box上设置fixed布局(不推荐)

.box{
	position: fixed;
	top:0;
	left:0;
	right:0;
	bottom:0;
	overflow-y: scroll;
}
四、正则空格匹配

匹配字符串头部和尾部的空格

str.replace(/(^\s*)|(\s*$)/g, "")

匹配空格校验

const reg = new RegExp(/\s/)
reg.test('000 shjh") // true
五、解构赋值的连续写法

1、解构赋值的连续写法

let obj = {a:{b:{c:1}}}
const {a:{b:{c}}} = obj
console.log(c)  // 1

2、连续结构赋值重命名

let obj2 = {a:{b:2}}
const {a:{b:data}} = obj2
console.log(data)  // 2
六、call,bind,apply的用法及区别

相同点:

1、都是改变this指向的
2、第一个参数都是this要指向的对象
	a)非严格模式下,若第一个参数指定,this为指定的参数值;若为null或undefined,则this指向window
	b)严格模式下,若第一个参数指定,this为指定的参数值;若为null或undefined,则this对应为null或者undefined
3、都可以利用后续参数传参

不同点:

1、call和bind的参数是依次传参,一一对应的;
2、但apply只有两个参数,第二个参数为数组
3、call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数
//  'use strict'
let fn = function (a,b) {
   console.log(this,a,b);
}
fn.call({type:'apply'},{a:'参数'},20); // {type:'apply'} {a:'参数'} 20
fn.call(null,{a:'参数'},20);  // window {a:'参数'} 20
fn.call(undefined,{a:'参数'},20); // window {a:'参数'} 20

const fs = fn.bind({type:'bind'},{a:'参数'},20) 
fs() // {type:'bind'} {a:'参数'} 20

fn.apply({type:'call'},[{a:'参数'},23]);  // {type:'call'} {a:'参数'} 20
七、数据类型及内存存储
1、数据类型分类
基本类型:
	* String
	* Number
	* Boolean
	* undefined
	* null
对象类型
	* Object:任意对象
	* Function:一种特别的对象(可以执行)
	* Array:一种特别的对象(数值下标)
2、数据类型判断
* typeof
    * 可以判断:undefined / 数值 / 字符串 / 布尔值 / function
    * 不能判断:null与object object和array
* instanceof  判断对象的具体类型
* ===
    * 可以判断undefined	
*  对象原型上的方法Object.prototype.toString()
//  typeof不能判断:null与object object和array
var a
a = null
console.log(typeof a, a===null) //'object' true
a = [1,2,3]
console.log(typeof a,"----") //object
//  instanceof  判断对象的具体类型
var b1 = {
    b2: [1, '1bc', console.log],
    b3: function () {
       return function () {
           return 'alshagh'
       }
    }
}
console.log(b1 instanceof Object, b1 instanceof Array) //true false
console.log(b1.b2 instanceof Array, b1.b2 instanceof Object) //true true
console.log(b1.b3 instanceof Function, b1.b3 instanceof Object) //true true
3、内存

JS中变量都是保存在栈内存中的

基本数据类型(String,Boolean...):
	* 基本数据类型的值直接在栈内存中存储
	* 值与值之间是独立存在,修改一个变量不会影响其他的变量
引用数据类型:(Object)
	* 对象的值是保存在堆内存中,每创建一个新的对象,就会在堆内存中开辟出一个新的内存空间
	* 而变量保存的是对象的内存地址(对象的引用),如果两个变量保存的是同一个对象引用
	* 当一个通过一个变量修改属性时,另一个也会受影响
// 基本数据类型
var c = 11
var d = c
c++
console.log(c) //12
console.log(d) //11
// 引用数据类型
var obj = new Object()
obj.name = '孙悟空'
var obj2 = obj
obj.name = '猪八戒'
console.log(obj.name) //猪八戒
console.log(obj2.name) //猪八戒

obj2 = null
console.log(obj) //{name:'猪八戒'}
console.log(obj2)//null   相当于把地址清空了断开了与obj的联系

/* 
    当比较两个基本数据类型的值时,就是比较值
    而比较两个引用数据类型时,它是比较的对象的内存地址
        如果两个对象是一模一样的,但是地址不同,它也会返回false
 */
var obj3 = new Object()
var obj4 = new Object()
obj3.name = '沙和尚'
obj4.name = '沙和尚'
console.log(obj3 === obj4) // false
4、undefined与null的区别
* undefined代表定义了但是未赋值
* null定义了并赋值了,只是值为null
5、什么时候给变量赋值为null
* 初始赋值,表面将要赋值为对象
* 结束前,让b指向的对象成为垃圾对象(被垃圾回收器回收)
八、this指向问题
1、 函数调用

函数名()和匿名函数调用,this指向window

function  fn1() {
    console.log(this)  // window --函数名调用
}
fn1()

;(function() {
    console.log(this) // window --匿名函数调用
})()

var fn2 = function(){
    console.log(this) // window --函数名调用
}
fn2()
2、 方法调用

this指向对象

var obj1 = {
    name: 'tom',
    setName: function() {
        console.log(this) // obj1对象
    }
}
obj1.setName()
3、 构造器调用

this指向实例化对象

function Person(){
    console.log(this) // 实例化对象p1
}
var p1 = new Person()
4、 间接调用

使用call和apply实现

this对应传的第一个参数
	如果不传值或者第一个值为null,undefined时this指向window(如果开启了严格模式则传啥是啥)
	如果传值,就是传的对应的值
function fn3() {
    console.log(this)
}
fn3.apply({name:'tom'})  // this为{name:'tom'}
fn3.call(8)  // this为8
5、 箭头函数中this

箭头函数没有自己的this,里面的this和定义有关,和调用无关
箭头函数的this指向是父级程序的this指向,如果没有父级程序或者父级程序没有this那么箭头函数的this执向是window。

;(() => {
    console.log(this) // window
})()

let arrowFun = () => {
    console.log(this) // window
}
arrowFun()

let arrowObj = {
    arrFun: function() {
        () => {
            console.log(this) // arrowObj对象
        }
    }
}
arrowObj.arrFun()
九、构造函数

构造函数与普通函数

相同点:创建方式相同
不同点:
	* 构造函数习惯上大写
	* 普通函数是直接调用,而构造函数需要使用new关键字来调用

备注:使用同一个构造函数创建的对象,我们称之为一类对象,也将一个构造函数称之为类
		我们将通过一个构造函数创建的对象,成为是该类的实例
function Person(name,age) {
    this.name = name
    this.age = age
    this.sayName = function () {
        console.log(this.name)
    }
}

var per = new Person("tom",18)
var per2 = new Person("mara",16)
console.log(per.name,per.age)
console.log(per.sayName === per2.sayName) // false  构造函数执行一次就会创建一个新的sayName方法

function Dog() {}
var d = new Dog()

console.log(per instanceof Person) //true
console.log(d instanceof Person) //false
十、原型链
* 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,它默认指向一个Object空对象(即称为: 原型对象)
* 原型对象中有一个属性constructor, 它指向函数对象
* 如果函数作为普通函数调用prototype没有任何作用
* 当函数以构造函数调用时,它所创建的对象中都会有一个隐含的属性,
	指向该构造函数的原型对象,我们可以通过__pproto__来访问属性
* 原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象
	我们可以将对象中共有的内容,统一设置到原型对象中
* 对象共有的属性和方法,可以统一添加到构造函数的原型对象中

图解1:
在这里插入图片描述

function MyClass() {}

MyClass.prototype.a = 123
MyClass.prototype.sayName = function(name) {
    console.log(name)
}
console.log(MyClass.prototype.constructor === MyClass) //true

var mc = new MyClass()
var mc2 = new MyClass()
console.log(MyClass.prototype === mc.__proto__) //true
console.log(mc.__proto__ === mc2.__proto__) //true

mc.a = '我是mc中的a' // 向mc中添加a属性
console.log(mc.a) // 对象的属性或方法首先会在自身中寻找,若没有才会去原型中寻找

in:检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
hasOwnProperty():检查对象自身中是否含有该属性时,只有对象自身中含有属性时才会返回true

onsole.log(mc.hasOwnProperty("name"))//false
console.log(mc.hasOwnProperty("hasOwnProperty")) //false 该方法在原型的原型里面
原型对象也是对象,所有它也有原型,
	当我们使用一个对象的属性或方法时,会先在自身中寻找
		* 自身中如果有,则直接使用
		* 如果没有则去原型对象中寻找,如果原型对象中有,则使用
		* 如果没有则去原型的原型中寻找,直到找到Object对象的原型
		* Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty"))//false
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")) //true
关于引用变量赋值问题:
	* 2个引用变量指向同一个对象,通过一个变量修改对象内部的值,另一个变量看到的是修改之后的数据
	* 2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一个引用变量依然指向前对象
var a = {age:12}
var b = a
a = {name:'tom', age:13}
b.age = 14
console.log(b.age, a.name, a.age) // 14 tom 13

function fn2 (obj) {
    obj = {age:15}
}
fn2(a)
console.log(a.age) //13

图解2:
在这里插入图片描述

问题: 在js调用函数时传递变量参数时,是值传递还是引用传递?

* 理解1:都是值(基本/地址值)传递
* 理解2:可能是值传递,也可能是引用传递(地址值)
十一、继承
1、原型链继承

关键点:子类型的原型为父类型的一个实例对象

function Supper() {
    this.subProp = 'Supper property'
}

Supper.prototype.showSupperprop = function () {
    console.log(this.subProp)
}

function Sub() {
    console.log(this.subProp)
}

// 子类型的原型为父类型的一个实例对象
Sub.prototype = new Supper()
// 让子类型原型的constructor指向子类型
Sub.prototype.constructor = Sub
Sub.prototype.showSubprop = function () {
    console.log(this.subProp)
}

var sub = new Sub()
sub.showSupperprop() //继承了父类的方法
sub.showSubprop()
sub.toString()

console.log(sub.constructor) //Sub

原型链继承图解:
在这里插入图片描述

2、构造继承

关键点: 在子类型构造函数中通用call()调用父类型构造函数

function Person(name, age) {
    this.name = name
    this.age = age
}
function Student(name, age, price) {
    Person.call(this, name, age) //相当于:this.Persaon(name, age)
    this.price = price
}

var s = new Student('Tom', 20, 24000)
console.log(s.name, s.age, s.price)
3、组合继承

关键点: 原型链+借用构造函数的组合继承

  1. 利用原型链实现对父类型对象的方法继承
  2. 利用call()借用父类型构建函数初始化相同属性
function Person(name,age) {
    this.name = name
    this.age = age
}
Person.prototype.setName = function (name) {
    this.name = name
}

function Student(name,age) {
    Person.call(this, name, age)
}
Student.prototype = new Person() //为了能看到父类型的方法
Student.prototype.constructor = Student //为了修正constructor方法

var s = new Student('Tom', 24)
s.setName('Bob')
4、extends继承
class Person {
    // constructor是构造方法
    constructor(name,age) {
        this.name = name
        this.age = age
    }
    speak() {
        console.log("Person的speak方法")
    }
}
class Student extends Person {
    constructor(name,age,sno){
        super(name, age)
        this.sno = sno
    }
    say() {
        console.log(this.name + "的年龄是" + this.age + ", 学号是" + this.sno)
    }
}
let s = new Student('tom',18,156786568)
s.speak()
s.say()
十二、arguments
在调用函数时,浏览器会传递两个隐藏的参数:
1、函数的上下文对象this
2、封装实参的对象arguments
    - arguments是一个类数组对象,它也可以通过索引来操作数据,也可获取长度
    - 在调用函数时,我们所传递的参数都会在arguments中保存
    - arguments.length可以用来获取实参的长度
    - 我们即使不定义形参,也可以通过arguments来使用实参 
        只不过比较麻烦
        arguments[0] 表示第一个实参
        arguments[0] 表示第二个实参
    - 它里边有一个属性叫做callee
        这个属性对应一个函数对象,就是当前正在指向的函数的对象
function fun() {
    console.log(arguments instanceof Array) //false
    console.log(Array.isArray(arguments)) //false
    console.log(arguments[0], arguments[1]) //tom 18
    console.log(arguments.length)
    console.log(arguments.callee)
}
fun('tom',18)
十三、IIFE

IIFE:立即执行函数
作用:隐藏实现/不会污染外部命名空间

// ()及[]的上一句语句要加;,避免修改时上一句不加,将;加到()/[]前面即可
;(function () {
    var a = 1
    function test () {
        console.log(++a)
    }
    window.$ = function () { //向外暴露一个全局函数
        return {
            test: test
        }
    }
})()
$().test() //1、$是一个函数 2、$执行后返回的是一个对象
十四、闭包

产生: 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
理解: 闭包是嵌套的内部函数

常见的闭包:
1、 将函数作为另一个函数的返回值

function fn1 () {
    var a = 2
    function fn2 () {
        a++
    }
    return fn2
}
var f = fn1()
f() //3
f() //4

2、将函数作为实参传递给另一个函数调用

function showDelay(msg, time) {
    setTimeout(function() {
        console.log(msg)
    },time)
}
showDelay('lilg', 2000)
十五、函数的防抖和节流

防抖和节流:限制函数的执行次数
使用场景: 不想频繁的触发事件(如搜索框实时发请求,表单验证,按钮提交事件,onmousemove,resize,onscroll等等)

html部分及通用js部分:

<input type="text">
<input id="input" type="submit">

var btn = document.getElementById("input")
// btn.addEventListener('click', submit, false)
// btn.addEventListener('click', debounce(submit, 2000), false)
btn.addEventListener('click', throttle(submit, 2000), false)

function submit(e) {
    console.log(e)
    console.log(this)
}
1、防抖

通过setTimeout的方式,在一定时间间隔内,将多次触发变为一次触发

function debounce(fn, timer) {
    var t = null
    return function() {
        var firstClick = !t
        if(t) clearTimeout(t)
        
        if(firstClick) {
            fn.apply(this, arguments)  // 修正submit中this指向和参数
        }
        
        t = setTimeout(() => {
            t = null
        }, timer)            
    }
}
2、节流

减少一定时间的触发频率

function throttle(fn, delay) {
    var begin = 0
    return function () {
        var cur = new Date().getTime()
        if(cur - begin > delay) {
            console.log(cur - begin)
            fn.apply(this, arguments)
            begin = cur
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的用Vue实现日常巡检记录单的示例: 首先,我们需要在HTML文件中引入Vue.js: ```html <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> ``` 然后,我们创建一个Vue实例并定义一个数据对象,其中包含了我们需要记录的巡检内容: ```html <div id="app"> <h1>日常巡检记录单</h1> <form> <label for="date">日期:</label> <input type="date" id="date" name="date" v-model="date"><br><br> <label for="name">巡检人:</label> <input type="text" id="name" name="name" v-model="name"><br><br> <label for="item1">巡检项目1:</label> <input type="text" id="item1" name="item1" v-model="item1"><br><br> <label for="item2">巡检项目2:</label> <input type="text" id="item2" name="item2" v-model="item2"><br><br> <label for="item3">巡检项目3:</label> <input type="text" id="item3" name="item3" v-model="item3"><br><br> <label for="item4">巡检项目4:</label> <input type="text" id="item4" name="item4" v-model="item4"><br><br> <input type="submit" value="提交" v-on:click.prevent="submitForm"> </form> </div> <script> var app = new Vue({ el: '#app', data: { date: '', name: '', item1: '', item2: '', item3: '', item4: '' }, methods: { submitForm: function () { // 这里可以将数据提交到后端进行处理 console.log(this.date, this.name, this.item1, this.item2, this.item3, this.item4); } } }) </script> ``` 在上面的示例中,我们创建了一个Vue实例,并将其绑定到一个id为“app”的div元素上。在Vue实例中,我们定义了一个数据对象,其中包含了我们需要记录的巡检内容,并定义了一个submitForm方法,用于在用户提交表单时处理数据。 在HTML中,我们使用v-model指令将表单元素与Vue实例中的数据对象进行绑定,以便在用户输入数据时自动更新Vue实例中的数据。我们还使用v-on指令将表单提交事件与submitForm方法绑定起来,以便在用户提交表单时调用该方法。 在submitForm方法中,我们可以在控制台中输出表单数据,或者将其提交到后端进行处理。 这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值