赞
踩
1.环境对象 this : 谁调用我,this指向谁
this相当于中文中的'我'
2.this指向取决于函数的调用,函数调用有三种方式
(1) 普通函数; 函数名() this->window
(2)对象方法: 对象名.方法名 this->对象
(3) 构造函数; new 函数名() this-> new创建的实例对象
一句话总结,this指向三选一 没点没new是window, 有new是实例,有点是点左边的对象
- <script>
- /*
- 1.环境对象 this : 谁调用我,this指向谁
- this相当于中文中的'我'
- 2.this指向取决于函数的调用,函数调用有三种方式
- 普通函数; 函数名() this-window
- 对象方法: 对象名.方法名 this-对象
- 构造函数; new 函数名() this-new创建的实例对象
- 一句话总结,this指向三选一
- */
- function fn(){
- console.log(this);
- }
- // (1)普通函数
- fn() //this -window
-
- //
- // (2)构造函数
- new fn() //this -new创建的实例对象
- let obj={
- name:'张三',
- eat:fn
- }
- // (3)对象方法
- obj.eat() //this-对象
- </script>
- <script>
- /*
- 环境对象 this :
- 普通函数;
- 对象方法:
- 构造函数;
-
- */
-
- //作用域链
- let obj = {
- name: "张三",
- eat: function() {
- console.log(this)
- function fn() {
- console.log(this)
- }
- fn()
- }
- }
-
- let eat = obj.eat
- obj.eat()
- </script>
1 函数名.call ({修改后的this指向},形参1,形参2…………)
- <script>
- /*
- 1.环境对象 this : 谁调用指向谁
- 普通函数;函数名() this-window
- 对象方法: 对象名.方法名() this-对象
- 构造函数; new 函数名() this-new构造的实例对象
- *** 默认情况下,函数内的this是固定的,无法被修改
- *** 如果想要动态修改函数内部的this指向,啧需要使用上下文调用方法
- * 上下文调用 :函数作用域 上下文指向 修改函数作用域内部this指向
- 2.上下文调用 :
- 2.1 函数名.call() call(修改的this,参数1,参数2)
- 2.2 函数名.apply()
- 2.3 函数名.bind()
- 3. 面试必问: call 和 apply 和 bind三者区别
- */
- function fn(a,b){
- console.log(this);
- console.log(a+b);
- }
- // 函数名.call(修改的this,参数1,参数2)
- fn.call({name:'张三'},10,20)
-
- </script>
//值类型
// 字符串 数字 布尔 undefined null
//引用类型
// 数组 函数 对象
函数名.call() 应用:万能数据类型检测
1.typeof 数据:检测数据类型,但是有两种数据类型无法检测
*typeof无法检测 数组和null两种数据类型得到的都是 object
2.万能数据类型检测 :Object.prototype.toString.call(数据)
加call的原因是 Object.prototype.toString 检测的是它自身的数据类型
- <script>
- /* 函数名.call() 应用:万能数据类型检测 */
-
- /*
- 1.typeof 数据:检测数据类型,但是有两种数据类型无法检测
- *typeof无法检测 数组和null两种数据类型得到的都是 object
- 2.万能数据类型检测 :Object.prototype.toString.call(数据)
- 加call的原因是 Object.prototype.toString 检测的是它自身的数据类型
- */
- //值类型
- // 字符串 数字 布尔 undefined null
- let str='abc'
- let num=123
- let bol=true
- let und=undefined
- let nul=null
-
- //引用类型
- // 数组 函数 对象
- let arr=[1,2,3]
- let fn=function(){}
- let boj={name:'张三'}
-
- // 万能检测:
- console.log(Object.prototype.toString.call(str)); // [object String]
- console.log(Object.prototype.toString.call(num)); // [object Number]
- console.log(Object.prototype.toString.call(bol)); // [object Boolean]
- console.log(Object.prototype.toString.call(und)); // [object Undefined]
- console.log(Object.prototype.toString.call(unl)); // [object Null]
- console.log(Object.prototype.toString.call(arr)); // [object Array]
- console.log(Object.prototype.toString.call(fn)); // [object Function]
- console.log(Object.prototype.toString.call(obj)); // [object Object]
- // (1)Object.prototype.toString()内部会返回this的固定类型,得到固定格式字符串‘[object 数据类型 ]’
- // (2)使用object原型中的toString()要想得到数据类型,只需要把this修改成你想要检测的对象
- </script>
函数名.apply() apply(修改的this,数组/伪数组)
apply会自动帮你遍历数组,然后按照顺序逐一传参
- <script>
-
- function fn(a,b){
- console.log(this);
- console.log(a+b);
- }
- // (1) 函数名.call(修改的this,参数1,参数2)
- fn.call({name:'张三'},10,20)
- // (2)函数名.apply(修改的this,数组/伪数组)
- // apply会自动遍历数组和伪数组 ,然后逐一传参
- fn.apply({name:'李四'},[50,60])
- </script>
apply()场景 :伪数组转真数组
伪数组: 有 数组三要素(下标,元素 ,长度),不能使用数组的方法
*伪数组的本质是 对象
- <script>
- /*
- apply()场景 :伪数组转真数组
- 伪数组: 有 数组三要素(下标,元素 ,长度),不能使用数组的方法
- *伪数组的本质是 对象
- */
- let obj={
- 0:10,
- 1:20,
- 2:30
- }
- console.log(obj);
- // 需求 有时候伪数组 想要使用真数组的方法 就需要把伪数组转换成真数组
- // (1)把伪数组的元素取出,push到真数组中
- let arr=[]
- // arr.push(obj[0],obj[1],obj[2])
- // console.log(arr)
- // (2)手动写循环遍历添加
- // for (let i = 0; i < obj.length; i++) {
- // arr.push(obj[i])
- // }
- // (3)arr.push.apply(arr,伪数组)
- // 这里使用apply不是为了修改this ,而是借助apply的传参特点: 自动遍历伪数组/数组传参 所以第一个参数应该写arr(保持this不变)
- arr.push.apply(arr,obj)
- console.log(arr);
-
- // ES6 伪数组转真数组,固定静态方法 Array.from(伪数组)
- let newArr=Array.from(obj)
- console.log( newArr);
- </script>
伪数组转真数组,固定静态方法 Array.from(伪数组)
let newArr=Array.from(obj)
console.log( newArr);
apply()场景 :求数组最大值
- <script>
- /*
- apply()场景 :求数组最大值
- */
- let arr=[4,845,65,8,99,24,3]
- // (1)js基础 :擂台思想
- let max=arr[0]
- for (let i = 1; i < arr.length; i++) {
- if(arr[i] >max){
- max=arr[i]
- }
-
- }
- console.log(max);
- // (2)js高级 Math.max
- let max1=Math.max.apply(Math,arr)
- console.log(max1);
- // ES6 :Math.max(...arr)
- // 功能类似于apply,也会自动的把数组给遍历
- let max2=Math.max(...arr)
- console.log(max2);
- </script>
1.环境对象 this : 谁调用指向谁
普通函数;函数名() this-window
对象方法: 对象名.方法名() this-对象
构造函数; new 函数名() this-new构造的实例对象
*** 默认情况下,函数内的this是固定的,无法被修改
*** 如果想要动态修改函数内部的this指向,则需要使用上下文调用方法
* 上下文调用 :函数作用域 上下文指向 修改函数作用域内部this指向
2.上下文调用 :
2.1 函数名.call() call(修改的this,参数1,参数2)
2.2 函数名.apply() apply(修改的this,数组/伪数组)
2.3 函数名.bind() 函数名.bind(修改的this)
*bind 不会立即执行函数,而是得到修改的this的新函数
*bind() 一般修改:定时器函数 ,事件处理函数
- <script>
-
- function fn(a,b){
- console.log(this);
- console.log(a+b);
- }
- // (1) 函数名.call(修改的this,参数1,参数2)
- fn.call({name:'张三'},10,20)
- // (2)函数名.apply(修改的this,数组/伪数组)
- // apply会自动遍历数组和伪数组 ,然后逐一传参
- fn.apply({name:'李四'},[50,60])
- //(3)函数名.bind(修改的this)
- //bind 不会立即执行函数,而是得到一个修改的this之后的新函数
- let newFn=fn.bind({name:'王五'})
- newFn(22,33)
- </script>
/* bind()场景: 修改定时器的this */
// 定时器中的this默认指向window,如果要修改定时器的this,就需要使用this
- <script>
- /* bind()场景: 修改定时器的this */
- // 定时器中的this默认指向window,如果要修改定时器的this,就需要使用this
- let fn= function (){
- console.log(this);
- }
- let newFn=fn.bind({name:'1111'})
- setTimeout(newFn,2000)
- // 上面代码可以简写一行
- // setTimeout(function(){}.bind(),2000)
- setTimeout(function(){
- console.log(this);
- }.bind({name:'李四'}),2000)
- /*
- 变量:是内存空间 只有存储功能,没有运算功能
- 变量只有两种语法 :存 ,取
- 字面量 :是数据 .只有运算功能,没有存储功能
- */
- // let arr=[10,20,30]
- // [10,20,30][0]
-
- </script>
3. 面试必问: call 和 apply 和 bind三者区别
相同点 都可以修改this指向
不同点
(1)传参方式不同 call是单个传参,apply是数组/伪数组传参
(2)执行机制不同 call和apply会立即执行函数,bind不会立即执行而是得到修改this的新函数
1.闭包closure是什么 : 两个条件 a:函数 b:函数内部还要访问 其他函数的变量
其他函数的变量不能是全局变量,也不能是自己的变量,必须是其他函数的
(1)闭包是一个 访问其他函数内部变量 的函数
(2) 闭包 =函数 + 上下文引用
2.闭包作用 : 解决变量污染
- <script>
- //num +fn1()组成了闭包
- let age=20
- function fn(){
- let num=20
- function fn1(){
- console.log(num);
- console.log(age);
- }
- fn1()
- }
- fn()
- </script>
- <script>
-
- // 打事件断点 从函数体开始 点击事件类型
- // 点击
- document.querySelector('.btn').addEventListener('click',function(){
- // (1)获取输入框文本
- let text=document.querySelector('input').value
- // (2)模拟网络请求
- setTimeout(function(){
- alert(`${text}的搜索结果为123456`)
- },1000)
- })
- </script>
1.递归函数: 一个函数 在内部 调用自己
* 递归作用和循环类似的,也需要有结束条件
1.递归函数: 在函数中调用自己
*递归类似于循环,也要有结束条件
- <script>
- /*
- 1.递归函数: 在函数中调用自己
- *递归类似于循环,也要有结束条件
-
- 2.递归应用:
-
- */
- function fn(){
- console.log('hh');
- // 递归调用
- fn()
- }
- // 双函数递归
- function fn1(){
- console.log('嘿嘿');
- fn2()
-
- }
- function fn2(){
- console.log('呵呵');
- fn1()
- }
- </script>
1. 浅拷贝与深拷贝 有两种实现方式
浅拷贝:拷贝地址,修改拷贝后的数据对原数据 有影响
深拷贝 :拷贝数据,修改拷贝后的数据对原数据 没有影响
2.深拷贝两种方式
(1) json方式 let newObj=JSON.parse(JSON.stringify(js对象))
*/
浅拷贝 :拷贝地址
浅拷贝如果是一层对象,不互相影响,可以直接拷贝值
如果是复杂类型的拷贝 ,出现多层拷贝会相互影响
- <script>
-
-
- let obj = {
- name:'张三',
- age:20,
- sex:'男',
- hobby:['吃饭','睡觉','学习']
- }
-
- let newObj=obj
- newObj.name='李四'
- console.log(obj.newObj);
- </script>
深拷贝拷贝的是对象,不是地址
常见方法
1,通过递归实现深拷贝
2.lodash/cloneDeep
3.通过JSON.stringfiy()实现
js库loadsh里面cloneDeep内实现了深拷贝
// json 深拷贝
// (1)JSON.stringify(js对象):把js对象 ->json字符串(json 底层会自动深拷贝)
- <script>
- let obj = {
- name:'张三',
- age:20,
- sex:'男',
- hobby:['吃饭','睡觉','学习']
- }
- // let json =JSON.stringify(obj)
- // (2) JSON.parse(json字符串) :json字符串 ->js对象
- // let newObj=JSON.parse(json)
- // 简写一行
- let newObj=JSON.parse(JSON.stringify(obj))
- newObj.name='李四'
- newObj.hobby[0]='游戏'
- console.log(obj,newObj);
-
- </script>
2.递归应用:
浅拷贝与深拷贝 :
json方式 let newObj=JSON.parse(JSON.stringify(js对象))
遍历dom树
如果是数据,直接进行拷贝 如果是数组或者对象 要 (1)声明一个空数组 (2)递归遍历旧的数组,把旧的数组里的数据追加给新的数组
(两者数组和对象的地址一样,所以修改新的数据的同时修改了旧的数据)
- <script>
- /*
- 1.递归函数:
-
- 2.递归应用:
- 浅拷贝与深拷贝 :
- json方式 let newObj=JSON.parse(JSON.stringify(js对象))
-
- 遍历dom树
- */
-
- let obj = {
- name:'张三',
- age:20,
- sex:'男',
- hobby:['吃饭','睡觉','学习'],
- student:{
- name:"班长",
- score:90
- }
- }
- // 深拷贝函数封装
- function kaobei(obj,newObj){
- // 遍历obj ,把里面的数据拷贝给newObj
- for(let key in obj){
- // 判断是不是数组,如果是数组还需要继续遍历拷贝
- if(obj[key] instanceof Array){
- // (1)声明一个空数组
- newObj[key]=[]
- // (2)递归遍历数组
- kaobei(obj[key],newObj[key])
- }else if(obj[key] instanceof Object){
- // (1)声明一个空数组
- newObj[key]=[]
- // (2)递归遍历数组
- kaobei(obj[key],newObj[key])
- }else{
- newObj[key]=obj[key]
- }
- }
- }
-
-
- </script>
递归遍历dom数 (了解)
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <meta http-equiv="X-UA-Compatible" content="ie=edge" />
- <title>Document</title>
- <style>
- * {
- padding: 0;
- margin: 0;
- }
-
- .menu p {
- width: 100px;
- border: 3px solid;
- margin: 5px;
- }
-
- .menu > div p {
- margin-left: 10px;
- border-color: red;
- }
-
- .menu > div > div p {
- margin-left: 20px;
- border-color: green;
- }
-
- .menu > div > div > div p {
- margin-left: 30px;
- border-color: yellow;
- }
- </style>
- </head>
- <body>
- <div class="menu">
- <!-- <div>
- <p>第一级菜单</p>
- <div>
- <p>第二级菜单</p>
- <div>
- <p>第三级菜单</p>
- </div>
- </div>
- </div> -->
- </div>
- <script>
- //服务器返回一个不确定的数据结构,涉及到多重数组嵌套
- let arr = [
- {
- type: "电子产品",
- data: [
- {
- type: "手机",
- data: ["iPhone手机", "小米手机", "华为手机"]
- },
- {
- type: "平板",
- data: ["iPad", "平板小米", "平板华为"]
- },
- {
- type: "智能手表",
- data: []
- }
- ]
- },
- {
- type: "生活家居",
- data: [
- {
- type: "沙发",
- data: ["真皮沙发", "布沙发"]
- },
- {
- type: "椅子",
- data: ["餐椅", "电脑椅", "办公椅", "休闲椅"]
- },
- {
- type: "桌子",
- data: ["办公桌"]
- }
- ]
- },
- {
- type: "零食",
- data: [
- {
- type: "水果",
- data: []
- },
- {
- type: "咖啡",
- data: ["雀巢咖啡"]
- }
- ]
- }
- ]
- // 封装一个添加菜单的函数
-
- function addElement (arr,father) {
- for(let i = 0;i<arr.length;i++){
- let div = document.createElement('div')
- div.innerHTML = `<p>${arr[i].type || arr[i]}</p> `
-
- father.appendChild(div)
-
- if(arr[i].data) {
- addElement (arr[i].data,div)
- }
- }
- }
-
- // 调用函数
- addElement (arr,document.querySelector('.menu'))
- </script>
- </body>
- </html>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。