微信小程序变量作用域
最近菜鸟看见了一篇文章,自打这之后,使用变量就不敢在page外面定义了
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
这看得菜鸟感觉这个page外面的变量就是王八蛋呀!文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
可是今天,我感觉不能轻信这种博客呀,不然难受呀,感觉会让人有种错误的认识,所以我今天自己来实验了文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
给大家看看目录结构:文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
实验一
既然他说不会随页面销毁而销毁,那我就试试吧!文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
首先在,dome.js的page外面定义变量文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
javascript
var a = "a"
Page({
onLoad:function (params) {
console.log(params)
}
})
然后在var.js里面:文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
javascript
onLoad: function (options) {
console.log(a)
}
结果很明显,报错:文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/15847.html
这我就很不理解呀!这博客骗人的??然后就到处请教大佬,于是得到结论:
Page外定义的是全局变量,在页面中要显示的就定义在data里面,不显示的,就可以定义在Page外面,每个页面都是一个独立的模块,当然其他页面获取不到的
如果要全局使用某些变量,可以放在app.js里面,在其他页面可以通过getApp()获取
心中感慨万千,大佬还是大佬,我什么时候才能这么强T_T,既然知道不如大佬,那我自然得再来研究研究
实验二
如果你在某个页面的page外,使用了全局变量
js
let change = false
需要其判断用户是否修改了页面内容,如果这样写:
js
Page({
menuName:function(e){ //监听用户是否改变input里面的值
if(e.detail.value!==this.data.menuName){
this.setData({
menuName:e.detail.value
})
change = true //全局变量
}
},
})
那如果用户修改后,按了返回键,那么当用户再次进入该页面,你的change依旧是true,但是这时你的页面内容由于是从数据库或云上取下的,所以还是以前的内容,这时候用户点击提交,没有修改也依旧提交上去了,会让用户误以为自己改了!
实验三
怎么样才能获得到其他页面定义的变量呢?突然灵光一闪,要不?把dome.js引入到var.js里面
搜到后菜鸟突然发现,这为什么写法不是微信小程序?
微信小程序不都是这样的吗?
XXXX:function(){
}
然后菜鸟自以为是的这样改了(dome.js):
javascript
var a = 1
Page({
out:function (e) {
return a;
}
})
module.exports = {
out:out
}
var.js引用代码:
javascript
var dome = require('../button/dome.js')
Page({
onLoad: function (options) {
console.log(dome.out())
}
})
然后等待我的只有报错:
顿时心生疑惑?这肯定是因为不是微信小程序,所以错了,但是搜来搜去都是这么个写法,然后我认真看了,发现,我就是菜鸟
原来别人是直接把公用的js代码提取出来,放到这个文件中,这个js并不是page的那种
然后,我就重新定义了,dovar.js
javascript
var a = 1
function out(e) {
return a;
}
module.exports = {
out:out
}
修改引入,正常运行!
实验四
javascript
var c = 3
var d ="d4"
var e = 10
Page({
data: {
c:4,
e:11,
},
onLoad: function (options) {
console.log(e)
console.log(this.data.e)
console.log(c)
console.log(this.data.c)
var c = 5
var d = 6
console.log(c)
console.log(this.data.c)
console.log(d)
},
onReady: function () {
console.log(c)
console.log(d)
},
})
结果:
结论:
1、data里面的变量名跟page外面的变量名重名没问题,打印出来互不相关
2、函数中的变量名跟page外面的重名则会覆盖,并产生变量的声明提升,从undefined跟5可以看出
实验五 --》 page外的数据和for循环的循环变量同名
代码:
js
var c = 3;
Page({
data: {
c:4,
},
onLoad: function (options) {
for(let c = 0;c<5;c++){
console.log('1 '+c);
}
for(let c = 0;c<c;c++){
console.log('2 '+c);
}
},
})
运行结果:
for循环的循环变量,会覆盖page外面的同名变量!
实验六 --》 for循环外的变量和循环变量同名
代码:
js
Page({
data: {
c:4,
},
onLoad: function (options) {
var a = this.data.c;
for(let a = 0;a<5;a++){
console.log(a);
}
},
})
运行结果:
for循环的循环变量,会覆盖for循环外面的同名变量!
实验七 --》 for循环操作for循环外的变量自加
i++
代码:
js
Page({
data: {
c:4,
},
onLoad: function (options) {
var i = this.data.c;
for(let a = 0;a<5;a++){
i=i++;
console.log(i);
};
console.log(i);
console.log(this.data.c);
},
})
运行结果:
+1
代码:
js
Page({
data: {
c:4,
},
onLoad: function (options) {
var i = this.data.c;
for(let a = 0;a<5;a++){
i=i+1;
console.log(i);
};
console.log(i);
console.log(this.data.c);
},
})
运行结果:
++i
js
Page({
data: {
c:4,
},
onLoad: function (options) {
var i = this.data.c;
for(let a = 0;a<5;a++){
i=++i;
console.log(i);
};
console.log(i);
console.log(this.data.c);
},
})
运行结果:
总结:
- for 循环里面的自加操作应该用 ++i 或者 +1
- i 的变化不会影响data中和其有关的值(普通类型)
实验八 --》 for循环操作data中的数组
代码:
js
Page({
data: {
arr:[]
},
onLoad: function (options) {
var d = this.data.arr;
for(let a = 0 ;a<5;a++){
d.push(a);
//var d = d.push(a); 报错:d.push not a function
//d = d.push(a); 报错:d is not defined
console.log(d);
};
console.log(d);
console.log(this.data.arr);
})
运行结果:
其操作为相互绑定,改变了d也同时改变了data中的arr
实验九 --》 for循环操作data中的对象
代码:
js
Page({
data: {
obj:{
name1:"wcz",
"name2":"wcz",
name3:1,
name4:[1,2,4],
"name5":[1,2,4],
class:"aaaa"
},
},
onLoad: function (options) {
var a = this.data.obj.name1;
a = a+"111";
console.log(a);
console.log(this.data.obj.name1);
var a = this.data.obj.name2;
a = a+"111";
console.log(a);
console.log(this.data.obj.name2);
var a = this.data.obj.name3;
a = a+1;
console.log(a);
console.log(this.data.obj.name3);
var a = this.data.obj.name4;
a.push(3);
console.log(a);
console.log(this.data.obj.name4);
var a = this.data.obj.name5;
a.push(3);
console.log(a);
console.log(this.data.obj.name5);
})
运行结果:
使用data中的对象a赋值给另外一个变量b,改变b的值,对象a不变化 (除非是数组,引用类型只有数组较为特殊)
解决方法:
菜鸟在网上搜的,那就是你赋值之前先将其这样(之前菜鸟比较菜)
var d = JSON.parse(JSON.stringify(this.data.arr));
那么,两者就不会相互干扰!具体原理根据vue推测:
感谢博主:
Gabriel_wei
这里其实更好的是用 lodash的cloneDeep函数,别人封装好的还是比这些奇技淫巧或者自己写的更靠谱!
js基本类型和引用类型的区别
1、基本类型:
我们知道基本的数据类型有:undefined,boolean,number,string,null 按值访问,可操作保存在变量中的实际的值,基本类型值指的是简单的数据段。
基本类型的值是不可变的!
在从一个变量向另一个变量赋值基本类型时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上:
js
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
此时,a中保存的值为 10 ,当使用 a 来初始化 b 时,b 中保存的值也为10,但b中的10与a中的是完全独立的,该值只是a中的值的一个副本,此后,这两个变量可以参加任何操作而相互不受影响。
基本类型的比较是值的比较:只要它们的值相等它们就相等。
还有下面的情况要注意哦!
js
var a = 1
var b = true;
console.log(a == b);//true
这是因为 == 是比较值相等就相等,而 === 是值和类型都相同时候才为true。其实这是类型转换和 == 运算符的知识了,也就是说在用 == 比较两个不同类型的变量时会进行一些类型转换。像上面的比较先会把true转换为数字1再和数字1进行比较,结果就是true了。 这是当比较的两个值的类型不同的时候 == 运算符会进行类型转换,但是当两个值的类型相同的时候,即使是 == 也相当于是 ===。
基本类型的变量是存放在栈区的(栈区指内存里的栈内存),栈区包括了 变量的标识符和变量的值。
类型转换又是一个重要的点,参考:
- 2021 亚鸿笔试题2
- 看Javascript实战详解 收获一
- js中获取数据类型
常见的类型转换面试题:
js
undefined == null; //true
undefined === null; //false
NaN == NaN; //false
NaN != NaN //true
typeof null; // Object
null instanceof object // false
// 比较过程
[] == ![]
// 将右边 ![] 进行转换
[] == false
// 隐式转换布尔值为数字
[] == 0
// 转换左边的 [],调用 [] 实例的 valueOf 方法
[] == 0
// valueOf 方法返回的不是基本类型值,再次调用 toString 方法
'' == 0
// 隐式转换字符串为数字
0 == 0
// 返回结果
true
// 比较过程
{} == !{}
// 将右边 !{} 进行转换
{} == false
// 隐式转换布尔值为数字
{} == 0
// 转换左边的 {},调用 {} 实例的 valueOf 方法
{} == 0
// valueOf 方法返回的不是基本类型值,再次调用 toString 方法
'[object Object]' == 0
// 隐式转换字符串为数字
1 == 0
// 返回结果
false
1 + '1' == '1' + '1' == '11'
true + true == 1 + 1 == 2
4 + [] == '4' + '' == '4'
4 + {} == '4' + '[object Object]' == '4[object Object]'
4 + [1] == '4' + '1' == '41'
4 + [1, 2, 3, 4] == '4' + '1, 2, 3, 4' == '41,2,3,4'
'a' + + 'b' == 'a' + 'NaN' == 'aNaN'
'true' == true // false
'true' === true // false
还有一个比较重要的就是字符串布尔型转布尔型:
2.引用类型
引用类型:引用类型有这几种:object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。
1.引用类型的值是可变的
当从一个变量向另一个变量赋值引用类型的值时,同样也会将存储在变量中的值的值复制一份放到为新变量分配的空间中。保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。那么赋值操作后,两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响:
js
var a = [1,2,3];
var b = a;
b.push(4);
alert(b); //[1,2,3,4]
alert(a); //[1,2,3,4] 对象类型 : 赋值不仅是值的复制,而且也是引用的传递
js
var a = [1,2,3];
var b = a;
b = [1,2,3,4];//相当于把[1,2,3,4]的地址给了b,使其和a的地址指向不同了,所以不会相互影响!
alert(b); //[1,2,3,4]
alert(a); //[1,2,3]
因此,引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操作都会相互影响。
2.引用类型的比较是引用的比较
js
var person1 = '{}';
var person2 = '{}';
console.log(person1 == person2); // true
上面讲基本类型的比较的时候提到了当两个比较值的类型相同的时候,相当于是用 === ,所以输出是true了。再看看:
js
var person1 = {};
var person2 = {};
console.log(person1 == person2); // false
可能你已经看出破绽了,上面比较的是两个字符串,而下面比较的是两个对象,为什么长的一模一样的对象就不相等了呢?
别忘了,引用类型时按引用访问的,换句话说就是比较两个对象的堆内存中的地址是否相同,那很明显,person1和person2在堆内存中地址是不同的。
所以这两个是完全不同的对象,所以返回false。
3.引用类型的值是同时保存在栈内存和堆内存中的对象
javascript和其他语言不同,其不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用,所以引用类型的值是按引用访问的。准确地说,引用类型的存储需要内存的栈区和堆区(堆区是指内存里的堆内存)共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。
评论