(function(){
var a = b = 100;
})();
console.log(typeof a);
console.log(typeof b);
函数整体结构是一个匿名函数,声明完后立即执行。
输出:
undefined
number
注意:var a=b=100;
实际上是:
(function(){
var a; //变量提升
b = 100; //定义不加var,全局变量
a = b;
})();
这里的b就成了全局变量,所以下面的输出就可以访问b。
var res=null instanceof Object;
console.log(res);
输出:
false
这里说一下:
typeof null === 'object';
这二者是全等的,从一开始出现JS就是这样。
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。
由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"。(reference)
ECMAScript提出了一个修复(通过opt-in),但被拒绝。这将导致typeof null === ‘object’。
不知道instanceof、in ?,点击这里
var val = 'a';
function f1(){
console.log(val);
var val = 'b';
console.log(val);
}
f1();
输出:
undefined
b
这题考的就是var声明的变量会变量提升,所以这题函数的结构实际上是这样的:
var val = 'a';
function f1(){
var val; //变量提升
console.log(val); //这里的val还没赋值,所以未定义
val = 'b';
console.log(val); //b
}
f1();
var array = [0, 1, 2, 3];
var spliceArray = array.splice(3, 1);
var sliceArray = array.slice(0, 1);
console.log(array);
输出:
[0,1,2]
这里只要明白 slice() 不会修改原数组,splice() 会影响原数组就OK了。
如果不知道这二者的区别,请阅读我的另外一篇博客。点击这里访问
var i=5;
for(i=0;i<10;i++){}
console.log(i);
//-----------------
let j=5;
for(j=0;j<10;j++){}
console.log(j);
//-----------------
var k=5;
for(var k=0;k<10;k++){} //for循环中 var 定义的变量也是全局变量
console.log(k);
//-----------------
let n=5;
for(let n=0;n<10;n++){} //let块级作用域
console.log(n);
输出:
10
10
10
5
console.log(typeof undefined == typeof NULL);
console.log(typeof function(){} == typeof class{});
输出:
true
true
注意,这里是NULL不是null要区分大小写,如果是null的话,typeof null为object输出为false,但这里是NULL所以为undefined。
class类(ES6)的数据类型就是函数,类本身就指向构造函数。所以typeof class{}为function。
[注意]:使用class类的时候,直接对类使用new命令,和构造函数的用法完全一致。
var tmp = {};
var A = function() {};
A.prototype = tmp;
var a = new A();
A.prototype = {};
var b = Object.create(tmp);
b.constructor = A.constructor;
console.log(a instanceof A);
console.log(b instanceof A);
输出:
false
false
instanceof 运算符是判断左侧的对象是否为右侧类的实例。
判断依据是对象的__proto__是否等于方法/类的prototype。
其次,这里Object.create();是什么作用?
Object.create()方法创建一个新对象,
使用现有的对象来提供新创建对象的对象的__proto__。
下面是直接通过输出__proto__和prototype验证结果:
请静下心,看完下面代码,一定要耐心看,细细体会,记住上面的知识点
var tmp = {};
var A = function() {};
//测试
console.log(A.prototype); //A {}
console.log(A.__proto__); //[Function],继承Function对象/类的所有属性/方法
A.prototype = tmp;
//测试
console.log(A.prototype); //{}
var a = new A();
//测试
console.log(a.__proto__); //{}
console.log(a.__proto__ === tmp); //true,这里的{}等于tmp
console.log(a.__proto__ === A.prototype); //true,这里A.prototype也等于tmp
A.prototype = {}; //A.prototype等于{}了,不是tmp了,只要把这句去掉,最后两句都是true了
//测试
console.log(A.prototype); //{}
console.log(a.__proto__ === A.prototype); //false
//复杂的数据类型,{}=={},{}==={} 均返回false
console.log(A.constructor); //[Function: Function]
//constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function。
var b = Object.create(tmp); //这时,b实例的原型就是tmp了
//测试
console.log(b.constructor); //[Function: Object]
b.constructor = A.constructor;
//测试
console.log(b.constructor); //[Function: Function]
console.log(b.__proto__); //{}
console.log(b.__proto__===tmp); //true
console.log(b.__proto__===A.prototype); //false
//结果
console.log(a instanceof A); //false
console.log(b instanceof A); //false
var arr=['a',,'b',,];
console.log(arr);
console.log(arr.length);
arr.push(1);
console.log(arr);
console.log(arr.length);
输出:
[ 'a', <1 empty item>, 'b', <1 empty item> ]
4
[ 'a', <1 empty item>, 'b', <1 empty item>, 1 ]
5
var array = [0,1,2];
var spliceArray = array.splice(0,1);
var sliceArray = array.slice(0,1);
var concatArray = array.concat("a");
console.log(array); //[ 1, 2 ]
console.log(spliceArray); //[ 0 ]
console.log(sliceArray); //[ 1 ]
console.log(concatArray); //[ 1, 2, 'a' ]
解析:这里只有splice会修改原数组。
忘记数组方法,点击这里
var name = 'World';
(function(){
if(typeof name === 'undefined'){
var name = 'JSON';
console.log("Goodbye " + name);
}else{
console.log("Hello " + name);
}
})();
输出:
Goodbye JSON
解析: 函数预编译不会看你if语句条件是否成立,会直接读变量声明语句,然后此时name发生变量提升,就是undefined。相当于以下代码:
var name = 'World';
(function(){
var name; //变量提升
if(typeof name === 'undefined'){
name = 'JSON';
console.log("Goodbye " + name); //Goodbye JSON
}else{
console.log("Hello " + name);
}
})();
function funcA(data) {
data.key = 'data';
}
function funcB(data) {
data = {};
data.value = 'data';
}
var data = {
key:'key',
value:'value'
}
funcA(data);
funcB(data);
console.log(data.key);
console.log(data.value);
输出:
data
value
解析: 注意这里的funcB(data)中的data是局部变量,相当于下列代码:
function funcA(data) {
data.key = 'data';
}
function funcB(data) {
var data;
/*
相当于在函数内部创建了一个新data对象,
所以data = {}修改的只是此时函数funcB内部的data,
如果在funcB内输出data.value,那么将会输出data,
但是在函数外部,data.value依然是value。
*/
data = {};
data.value = 'data';
}
var data = {
key:'key',
value:'value'
}
funcA(data);
funcB(data);
console.log(data.key);
console.log(data.value);
var y=0;
var x=1;
function f1(n){
n+=1;
return n;
}
function f1(n){
n+=3; //这里n为局部变量
return n;
}
y=f1(x);
console.log(y);
输出:
4
解析:假如有多个同名函数,则以最后一个函数为调用基准
var a=1;
setTimeout(function(){
console.log(a);
a=10;
console.log(a);
},0);
a=100;
console.log(a);
输出:
100
100
10
解析:需要知道事件循环机制才可以理解这道题,这里的setTimeout定时器异步任务挂起,最后才执行里面的代码。
for(var i=0;i<5;i++){
setTimeout(()=>{
console.log(i);
},200);
}
输出:
5
5
5
5
5
解析:这题也是事件循环机制。
for(var i=0;i<5;i++){
(function(num){
setTimeout(()=>{
console.log(num);
},200);
})(i);
}
输出:
0
1
2
3
4
解析:这里在for循环内部使用了一个闭包,使用num存储每次循环的i值,这样定时器最终执行时,输出的是每次闭包存储的i值,而不是最终的i值。
function numAdd(num){
num++;
console.log(num);
}
setTimeout(numAdd,1000);
输出:
NaN
解析:因为num为undefined,经过num++所以成了NaN。