###JS学习中的坑
####1、未经定义的变量就使用就会报错,但是在"typeof"里面唯一不报错,显示的是“undefined”
var x = 1;
if(function f(){}){
x += typeof f;
}
console.log(x);//打印 1undefined
**一旦变量未经定义就使用,肯定会报错;但是唯一不报错的就是放在typeof 里面 并且返回的是undefined;**
typeof x;--> "string"
####2、让函数打印出0-9 的数字
function test(){
var arr = [];
for(var i = 0; i < 10; i++){
arr[i] = function(){
console.log(i);
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}
结果是打印出十个10;
因为函数不是在console.log()的时候就打印出来,是把函数保存在外面,形成十个产生闭包的函数,十个函数共用一个作用域,并且访问的时候都是 10,这是一对十的方法,思路就是让他变成一对一的方式。
####正确的做法是"利用立即执行函数"
实现的就是在执行到(function(j){}(i))这个函数的时候就“变现”
function test(){
var arr= [];
for(var i = 0; i < 10; i++){
(function(j){//立即执行函数
arr[j] = function(){
console.log(j);
}
}(i))
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10;j++){
myArr[j]();
}
###3、*!!!原始值不能有属性值和方法,能访问是隐式发生 new String(‘abcd’).length之后销毁
var str = "abcd";
str.length = 2;//系统执行之后就销毁
console.log(str);-->结果打印的是 abcd
典型题目
var str = "abc";
str += 1;//string 类型
var test = typeof(str);//test == "string"
if(test == 6) {
test.sign = "typeof 的返回结果可能是 String";
}
console.log(test.sign);-->undefined
###4、形参实参相映射,牵一发而动全身
下面alert的结果是什么
function arguments(a,b,c){
test[2] = 10;
alert(c);//打印结果为 10
}
arguments(1,2,4);
如果函数体改为下面,结果又会是什么?
c = 10;
alert(test[2]); //结果也是 10
##5、原型的误区
Person.prototype.name = 'rainy';
function Person(){
// var this ={__proto__:Person.prototype}
}
var person = new Person();
Person.prototype.name = 'vita';
console.log(person.__proto__name);//打印的就是 'vita'
下面的例子先new对象再来改变属性跟** new 对象之前改变属性是不一样**的
Person.prototype.name = 'rainy';
function Person(){}
var person = new Person();
Person.prototype = {
name:'vita'
}
console.log(person.__proto__name);//打印的却是'rainy'?
Person.prototype.name = 'rainy';
function Person(){}
Person.prototype = {
name:'vita'
}
var person = new Person();
console.log(person.__proto__name);//打印的却是'vita'?
####基础例子
var obj.prototype = {name:‘a’}
var obj1 = obj;//打印 a
obj.prototype = {name:‘b’}
####稍微难一点的问题
//这里有个小知识
sayName 里面的this 指向是,谁调用的这个方法,this就指向谁
Person.prototype = {
name:'c',
sayName:function(){
console.log(this.name);
}
}
function Person(){
this.name = 'b';
}
var person = new Person();
console.log(person.name);//打印的是 b
###对象
!!!绝大多数对象最终都会继承自Object.prototype;
例外的是 Object.create(null);
##笔试题目
###逗号运算符
var f = (
function f(){
return “1”;
},
function g(){
return 2;
}
)();
typeof f;//"number"
f; // 打印出2
##undefined 在typeof就可以用
var x = 1;
if(function f(){}){
x +=typeof f;
}
x;//打印"1undefined"
##基础知识点
undefined == null //true;
{}=={} //false
var obj = {};
var obj1 = obj;
obj1 ==obj;//true;
obj1 ===obj; //true 比对的是指向的地址
##弄懂this 的指向
var name = '222';
var aa = {
name:'111',
say:function(){
console.log(this.name)
}
}
var fun = aa.say;
fun(); //this-->window
aa.say();//this-->aa; 打印的是111
var b = {
name:'333',
say:function(fun){
console.log(this);//指向的是b;
fun();//实际上就是把aa.say函数放在这里,没人调用他 this--->window
}
}
b.say(aa.say); //222
b.say = aa.say(); //111
###arguments.callee用处 指向函数的引用
在立即执行函数计算阶乘的时候的只能用
var num = (function(n){
if(n==1){
return 1;
}
return n * arguments.callee(n-1);
}(10));
num; //3628800
##arguments 下面只有callee 跟length;caller指向的是函数被调用的环境
例如下面的例子
function call(){
console.log(arguments.callee);//指向的是call
function test(){
console.log(arguments.callee);
}
test();//指向的是test
}
call();
function test(){
demo();
}
function demo(){
console.log(demo.caller);
}
test(); // 打印的结果是test(){demo();} caller指向的是调用它的环境 是test();在'use strict'模式下caller 会报错
下面打印的结果是什么;
var foo =123;
function print(){
this.foo = 234;
console.log(foo);
}
print();// 234 this--->window
var foo =123;
function print(){
//var this = Object.create(print.prototype)
this.foo = 234;
console.log(foo);
}
new print();// 123 访问的foo 不是this.foo
2、使用test() 和new test()打印下面的结果分别是
var a = 5;
function test(){
a = 0;
console.log(a); //-->0
console.log(this.a); //-->5 this 指向的是window
var a;
console.log(a); //-->0
}
test();
new test(); //分别是 0 undefined 0
分析test()
AO{
a:undefined;-->0
this:window;--->5
}
3、判断传入的参数是不是NaN类型
function myIsNaN(num){
var ret = Number(num);
ret +="";
if(ret =="NaN"){
return true;
}else {
return false;
}
}
4、print()();第一个括号返回的是函数,第二个括号返回的是结果
Var obj = {a:"002"}
function print(){
obj.a = "a";
Object.prototype.b = "b";
return function inner(){
console.log(obj.a);//a
console.log(obj.b);//b
}
}
print()();
5、浅层实现克隆obj 对象到obj1,obj1改变obj也改
var obj = {
name:"a",
sex:"male"
}
var obj1 ={}
function clone(origin,target){
var target = target||{};//防止用户不传参数,就自己定义一个空对象
for(prop in origin){
target[prop] = origin[prop];
}
return target;//如果没传target就要把target return 出去
}
clone(obj,obj1);
obj1;//{name: "a", sex: "male"}
6、深度拷贝
var obj = {
name:"a",
sex:"male",
card:['visa','master'],
wife:{
name:"bcd",
son:{
name:"aa"
}
}
}
var obj1 = {}
function deepClone(origin,target){
//思路:遍历对象 for(var prop in obj)
1、判断是不是原始值 typeof() 不是object
2、判断是数组还是对象 (3种方法instanceof toSring(建议用这种) constructor)
3、建立相应的数组或对象
递归
var a = {
name:'vita',
age:23,
card:['master','visa'],
wife:{
name:'haha',
son:{
name:'a'
}
}
};
var b = {};
function deepClone(origin, target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = '[object Array]';
for(var prop in origin){
if(origin.hasOwnProperty(prop)){//要origin本身具有的属性,不是继承来的
if(typeof(origin[prop]) !=="null" &&typeof(origin[prop])== "object"){//判断形参是否是原始值,
if(toStr.call(origin[prop])==arrStr){
target[prop] = [];
}else {
target[prop] = {};
}
deepClone(origin[prop],target[prop]);
}else {
target[prop] = origin[prop];
}
}
}
return target;
}
测试:a.card.push('lo');//["master", "visa", "lo"]
b.card; // ["master", "visa"]
这就实现了改变a 不会改变b 的拷贝
###类数组对象
阿里巴巴笔试题
var obj = {
"2":"a",
"3":"b",
"length":2,
"push":Array.prototype.push
}
obj.push('c');
obj.push('d');
//打印的结果是
obj = {2: "c", 3: "d", length: 4, push: ƒ}
要明白push 的内部原理
Array.prototype.push = function(target){
obj[obj.length] = target;//obj[索引] = target;
obj.length++;
}
###6、执行下面
var h = function a(){
return 23;
}
typeof a();
报错 a is no deifined 在这里 函数名a可以省略