例题一:下面能输出1,2,3,4,5的是
第一种:
function foo(){
bar.apply(null,arguments); //相当于直接调用bar(aguements);
}
function bar(){
console.log(arguments);
}
foo(1,2,3,4,5);
控制台打印结果
第二种:可以执行打印
function foo(x){
console.log(arguments);
return x;
}
foo(1,2,3,4,5);
第三种:不报错,打印不了
function foo(x){
console.log(arguments);
return x;
}(1,2,3,4,5);
第四种:可以执行
(function foo(x){
console.log(arguments);
return x;
})(1,2,3,4,5); //立即执行函数
例题二:
function b(x,y,a){
arguments[2] = 10;
alert(a); //print 10 形参和实参相映射,但是本质上无关,如果将代码改变为a = 10; alert(arguments[2]);也会打印出10
}
例题三:
var f = (
function f(){
return "1";
},
function g(){
return 2;
}
)();
console.log(typeof(f)); //print number,因为f是一个立即执行函数,实际执行的函数是逗号表达式的最后一个函数,也就是g()
例题四
var x = 1;
if (function f(){}) { //函数f被括号括起来被当做一个表达式,返回结果为true,但是代价就是f会被立即销毁,typeof f,就相当于typeof 字符串,返回结果是undefined所以x+=typeof f就是一个数字加一个字符串,直接连接,结果是1undefined
x += typeof f;
}
console.log(x);
例题五 判断题
function myNaN(a){
var ret = Number(a);
ret += "";
if (ret == "NaN") {
return true;
}else{
return false;
}
}
结果
this指向详解
1.函数预编译过程this——>window
2.全局作用域里this——>window
3.call/apply可以改变函数运行时this指向
4.obj.func();func()里面的this指向obj
相关例题
var name = "222";
var a = {
name : "111",
say : function(){
console.log(this.name);
}
}
var fun = a.say;
fun(); //print 222,全局调用,this指向window
a.say(); //print 111,a调用函数say,this指向a
var b = {
name : "333",
say : function(fun){
fun();
}
}
b.say(a.say); //print 222,a.say作为参数传进fun中,因为fun函数是直接调用的,不是某个对象调用,所以仍然是在全局调用,所以this还是指向window
b.say = a.say;
b.say(); //print 333,b对象调用函数say,this指向b
arguments
arguments.callee
举例一
var num = (function (n){
if(n == 1){
return 1;
}else{
return n * arguments.callee(n-1);
}
}(20))
举例二
function test(){
console.log(arguments.callee); //argument.callee在哪个函数内,就打印的是哪个函数,print test()
function demo(){
console.log(arguments.callee); //print demo()
}
demo();
}
test();
控制台打印结果
func.caller
function test(){
demo();
}
function demo(){
console.log(demo.caller); //caller是函数自带的一个属性,指代函数被调用的环境
}
test();
控制台打印结果
例题五
this指向问题
var foo = '123';
function print(){
var foo = '456';
this.foo = '789'; //这个this.foo指的是全局里的foo即把原来的foo = ‘123’ 修改为 foo = ‘789’
console.log(foo); //这个foo指的是print内部的foo,即Ao里面的,离得最近的,(如果打印的是this.foo,那么,结果是789,如果注视掉上一行,this.foo的结果是123)
}
print(); //print 456
例题六
执行test
var a = 5;
function test(){
a = 0;
alert(a); //alert 0
alert(this.a); //alert 5
var a;
alert(a); //alert 0
}
test();
new test
var a = 5;
function test(){
a = 0;
alert(a); //alert 0
alert(this.a); //alert undefine
var a;
alert(a); //alert 0
}
new test(); //new一个test,就是创建一个this对象,而这个对象上面是没有a的所以第二个打印的是undefined
例题七
function print(){
console.log(foo); //undefined
var foo = 2;
console.log(foo); //2
console.log(hello); //报错,Uncaught ReferenceError: hello is not defined
}
print();
例题八
function print(){
var marty = {
name : "marty",
printName : function(){console.log(this.name);}
}
var test1 = { name : "test1"};
var test2 = { name : "test2"};
var test3 = { name : "test3"};
test3.printName = marty.printName;
var printName2 = marty.printName.bind({name:123});
marty.printName.call(test1); //print test1
marty.printName.apply(test2); //print test2
marty.printName(); //print marty
printName2(); //print 123
test3.printName(); //print test3
}
print();
例题九
var bar = {a:"002"};
function print(){
bar.a = 'a';
Object.prototype.b = 'b';
return function inner(){
console.log(bar.a); //print a
console.log(bar.b); //print b
}
}
print()();
js深度克隆
js对象组成
说对象的深度克隆之前,要先明白js中对象的组成。以一句话说js中一切皆对象
具体数据类型分为两种:
-原始数据类型:其中存储的是对象的实际地址。eg number,string,boolean,还有两个特殊的null,undefined
-引用数据类型:其中存储的是对象的引用地址。eg array ,function,object
克隆的概念
浅层克隆:原始类型为值传递,对象类型仍为引用传递。
深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象。
例题十
浅层克隆,即原始值的克隆,克隆后的两个对象里面的东西互不影响,看下面控制台的打印结果
var obj ={
name : 'abc',
age : 123,
sex : 'female'
}
var obj1 = {}
function clone(origin,target){
var target = target || {}; //容错
for(var prop in origin){
target[prop] = origin[prop];
}
return target;
}
clone(obj,obj1);
深度克隆:如果对象中含有引用值,继续使用浅层克隆,引用值的修改会互相影响,深度克隆解决了这个问题
var obj = {
name : "abc",
age : 123,
card : ['visa','master'],
wife : {
name : "bcd",
son : {
name : "aaa"
}
}
}
var obj1 = {}
function deepClone(origin,target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[Object Array]";
for(prop in origin){
if(origin.hasOwnProperty(prop)){
if(origin[prop] !== "null" && typeof(origin[prop]) == 'object'){
if(toStr.call(origin[prop] == arrStr)){ //1
target[prop] = []; //2
}else{ //3
target[prop] = {}; //4
} //5
deepClone(origin[prop],target[prop]);
}else{
target[prop] = origin[prop];
}
}
}
return target;
}
//1.判断是不是原始值 1.typeof() object instanceof toString constructor,instanceof在跨父子域的时候又问题,比如在子域建立的空数组【】instanceof父域的arry,返回是false,toString没有问题
//2.判断是数组还是对象
//3.建立相应的数组或对象
上述代码的1-5的标记行,还可以用三目运算符来简化一下如下
target[prop] = (toStr.call(origin[prop] == arrStr) ? [] : {};