this指向-作用域、作用域链-预解析 变量提升-Vue组件传值 父子 子父 非父子-Vue数据双向绑定原理
目录
- this指向
- 作用域、作用域链
- 预解析 变量提升
- Vue组件传值 父子 子父 非父子
- Vue数据双向绑定原理
1.this指向
函数的this指向 看调用、不看声明
(1)普通函数调用
①函数名() this->windown
(2)事件处理函数调用
①oDiv.onclick = function(){} this->添加事件的元素
1.1 onclick 点击事件
1.2 onload 用户进入某个页面的时候触发(onload 事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。)
1.3 onunload 用户离开某个页面的时候触发(onload 和 onunload 事件可用于处理 cookie。)
1.4 onchange 内容变化事件(常结合对输入字段的验证来使用)
1.5 onmouseover 鼠标移动到HTML元素上方的事件
1.6 onmouseout 鼠标移出HTML元素上方的事件
1.7 onmousedown 鼠标按下的时候触发的事件
1.8 onmouseup 鼠标弹起触发的事件(onmousedown,onmouseup和onclick区别,onclick是鼠标完成点击事件的时候触发的事件)
1.9 onfocus 元素获取焦点事件
1.10 onblur 元素失去焦点事件
1.11 onabort 图像的加载失败
1.12 ondblclick 双击事件
1.13 onerror 当加载图像和文档时发生错误
1.14 onkeydown 键盘按键被按下发生的事件
1.15 onkeyup 键盘按键被松开发生的事件
1.16 onkeypress 键盘按键按下并松开发生的事件
1.17 onmousemove 鼠标移动
1.18 onresize 窗口或者框架被重新调整大小
1.19 onselect 文本被选中
1.20 onreset 重置按钮被点击
1.21 onsubmit 提交按钮被点击
(3)全局中this指向window对象
(4)对象的方法函数
Var obj = {fn:function(){}}
对象名.方法名() obj.fn(); this->调用方法的对象(对象名)obj
例1.普通函数this默认指向window
function fun(){
console.log(this) //window
}
fun() //相当于window.fun()
例2.对象的方法 对象.方法调用this指向该对象
let obj={
name:'胡歌',
age:"18",
speak(){
console.log(this.name+'今年'+this.age,this)
//胡歌今年18 this指向这个对象
}
}
obj.speak() //谁调用这个方法指向谁
例3.函数谁调用指向谁
function constructorFun(name='虹猫蓝兔七侠传',age='16'){
this.name=name;
this.age=age;
this.speak=function(){
console.log(this.name+'的年龄是'+this.age,this)
}
}
let childObj = new constructorFun('胡歌',20)
childObj.speak()
//胡歌的年龄是20 this指向childObj这个对象
//this指向实例
//比如:vue实例 就是new出来的 在使用中通常会使用this点方法名来使用方法,这些方法都是vue这个类上面的方法。
例4.事件对象 谁触发事件指向谁
<div id="box">我是id=box盒子</div>
let boxid = document.getElementById('box')
boxid.onclick=function(){
console.log(this) //指向box这个dom对象
this.innerHTML='我是用this改变后的innerHTML'
}
例5.箭头函数this指向外层作用域的this
<div class="box">我是class=box盒子</div>
let boxclass = document.getElementsByClassName('box')[0]
boxclass.onclick=()=>{
console.log(this) //当前作用域外层this指向window
this.alert('我是window对象')
}
总的来说:
①方法函数:对象.方法() ; this->调用方法的对象
②普通函数:( window.) 函数名() this->window
③事件处理函数: oDiv.οnclick= function(){} oDiv.onclick() this->添加事件的元素
④全局中的this指向window对象
2.作用域、作用域链
它是指对某一变量和函数具有访问权限的代码空间
在js中只有两种作用域
1.全局作用域:script标签内部的区域就是全局作用域
2.局部作用域:函数大括号内部的区域就是局部作用域
在js中只有函数可以划分作用域,因此每个函数的大括号内部都是一个局部作用域
window.onload = function () { //在这里再写上你的函数 }
因此我们称局部作用域为函数作用域
1.全局变量 声明在全局的变量
2.全局作用域就是全局变量起作用的范围
3.局部变量 在函数内部声明的变量
4.局部作用域就是局部变量起作用的范围
<script>
//script标签中的空间就是全局作用域
//全局作用域
//a变量就声明在了全局作用域,就是一个全局变量
var a; //全局变量
a(a)
a = 10;
function a(a) {
//函数大括号内局部作用域
//在函数内部声明的变量就是局部变量
let b = 10;//局部变量
console.log(a)
a = 100
}
console.log(a)
console.log(b) //b is not defined
var c;
console.log(c)//undefined
</script>
作用域链
会先在当前作用域查找变量,当前没有向上一级查询
1.当前有使用当前的变量。
首先,函数不调用不执行,所以调用了fun函数,在fun函数中,有一个函数a,调用了函数a,打印了a,调用a会执行a函数,里面var了一个a赋值为10,所以在函数a中打印a出的结果为10,在fun函数中打印a的结果是函数a这个函数体。
2.当前没有向上一级查找变量,一直到全局作用域为止,如果还是没有会报错,xxx is not defined。
var c = 100;//全局作用域中有c
function num(b) {
//上一级函数局部作用域也没有c
var a = 10;
function sum() {
console.log(a + b + c) //当前函数局部作用域没有c
}
sum()
}
// num(10) //10+10+100
num(10) //120
3.浏览器预解析变量提升
提升的对象包括:
1.函数声明
2.变量声明
3.函数内部作用域默认形参声明
1.函数声明和变量声明是同一个变量名
当函数声明和变量声明冲突的时候,变量声明无法覆盖函数声明,变量赋值可以覆盖函数声明 所以最后结果为10
具体代码:
a(a) //调用函数
a = 10; //变量
var a; //全局变量
//或者 var a = 10; 同上面两句
function a(a) { //函数
}
console.log(a)//10
浏览器对js代码的预解析,这是代码执行之前的操作,也叫变量提升。
函数和定义变量会被提升到当前作用域最顶端,当函数名和定义变量名字一样时,函数名会覆盖变量定义。
预解析完成后的代码:
//上面预解析完成后是
function a(a) {
}
a(a) //调用函数
a = 10; //给变量a重新赋值覆盖函数体
console.log(a)//10
2.函数形参和变量声明是同一个变量名
a(a) //调用函数
a = 10; //变量
b=20;//变量
var a; //全局变量
function a(a) { //函数
var a = 100;
b=200
console.log(a,b) //100 200
}
var b;
console.log(a)//10
当函数调用的时候,就要进入函数的局部作用域 浏览器还要重新再局部作用域中进行预解析,变量名定义提前 赋值不会提前。
1.参数的传递和函数中变量名冲突,函数形参的值会覆盖预解析的效果
2.在函数执行之前进行预解析,这时候参数还没传递
3.预解析以后 函数内代码开始执行 传参
4.在函数中如果没有定义这个变量 就要在全局作用域中查找
5.赋值的时候函数中没有这个变量根据作用域链也会将全局这个变量的值发生改变
函数体内正常预解析代码,没有形参参与:
var b;
function a(a) { //函数
var a;
a = 100;
b = 200
console.log(a, b)
}
a(a) //调用函数
a = 10; //变量
b = 20;//变量
console.log(a)//10
函数开始执行,形参接受到实参的时候:
var b;
function a(a) { //函数
var a =a; //定义a为形参a 参数
a = 100; //被重新赋值
b = 200
console.log(a, b) //100 200
}
a(a) //调用函数
a = 10; //变量
b = 20;//变量
console.log(a)//10
console,log(b)//20
在执行函数的时候,函数内部有用到b,并且被重新赋值,b由undefined变成200,改变全局变量的值,在后面的同步代码中b又被重新赋值,所以最终打印b的值为20。
数组的引用地址
下面的代码在浏览器运行
var arr = [3, 4];
console.log(arr);
arr.push(5);
console.log(arr);
运行结果为:
点开看到第二行打印,里面还有5
实际第二行代码打印的就是[3,4],但是由于数组是引用数据类型(复杂数据类型),内存地址是一样的,显示的是原来的结果。但包含修改后的结果.(浅拷贝,拷贝栈里面的指针)
第一次打印的时候,内存地址还没有变,第二次打印的时候已经发生了变化,点开第一次打印,所指向的内存地址已经发生了变化,进而数组项数据也发生了变化。
ie: 11 跟不上进度
var arr = [3, 4];
let brr=arr;
brr.push(5)
console.log(arr); 3 4 5
4.Vue组件传值 父子 子父 非父子
1.父子
//父 引入子组件 注册 使用 绑定属性 绑定方法
<v-child :abc="a" @zjq="num"></v-child>
//子 props接受 在views使用 {{}}
props: ["abc"],
我是父组件传过来的 {{abc}}
2.子父
// 父
<v-child :abc="a" @zjq="num"></v-child>
//子
<button @click="CHILDRENfun">我是子组件的按钮</button>
CHILDRENfun(){
this.$emit('zjq','我是子组件来的数据')
}
//父
num(item) {
console.log("我是父组件的方法,num", item);
}
3.1非父子
```javascript
// main.js文件
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
Vue.prototype.$eventsBus = new Vue()
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
//1 触发方法
/ <button @click="getBroFun">children按钮</button>
getBroFun(){
this.$eventsBus.$emit('zzz',123)
},
//2监听方法
this.$eventsBus.$on('zzz',(num)=>{
console.log(num)
})
3.2 下载events模块
Events.js
const EventEmitter = require('events')
const ee =new EventEmitter()
export default {ee}
Main.js
import events from './assets/js/events'
Vue.prototype.$events = events.ee
//1 触发方法
getBroFun() {
this.$events.emit("asd", 123);
},
//2监听方法
this.$events.on("asd", num => {
console.log(num);
this.num = num;
});
5.Vue数据双向绑定原理
点击链接直通车 == > 大佬详细介绍Vue原理
new Vue() ==> Observer数据劫持 ==> 绑定Dep ==> 通知watcher ==> 更新视图
new Vue() ==> Compile解析模板指令 ==> 初始化视图 和 绑定watcher
Observer :数据监听器,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者,内部采用Object.defineProperty 的 getter 和 setter 来实现
Dep :订阅者收集器或者叫消息订阅器都可以,它在内部维护了一个数组,用来收集订阅者,当数据改变触发 notify 函数,再调用订阅者的 update 方法
Watcher :订阅者,它是连接 Observer 和 Compile 的桥梁,收到消息订阅器的通知,更新视图
Compile :指令解析器,它的作用对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数
Updater:视图更新
阿里面试题
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
};
Foo.prototype.getName = function () {
console.log(3);
};
var getName = function () {
console.log(4);
};
function getName() {
console.log(5);
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
本文地址:https://blog.csdn.net/qq_43291759/article/details/109647298
下一篇: 一文让你彻底明白C++中的const