《Effective Javascript》

对象隐式转换

/*对象通过toString()和toLocaleString()隐式转换成字符串,通过valueOf隐式转换成数值;
 在进行强转字符串类型时将优先调用toString方法,强转为数字时优先调用valueOf。
*/
"js"+{toString:function(){return "123";}} //js123
1=={valueOf:function(){return true;}} //true;

var color=["red","green","blue"];
color.toString();//"red,green,blue"
color.valueOf();//["red","green","blue"]

闭包

定义:有权访问在另一函数作用域内变量的函数叫做闭包;
特性:当一个函数返回它内部定义的一个函数时,就产生了一个闭包,闭包不但包括被返回的函数,还包括这个函数的定义环境。
闭包的三个特点:

  • 闭包允许当前函数使用在外部函数定义的变量
//函数可以引用定义在其外部作用域的变量
function makeSandwich(){
    var magicIngredient="peanuts butter";
    function make(filling){
        return magicIngredient+ " and "+filling;
    }
    return make("jelly");
}
makeSandwich(); //"peanuts butter and jelly"
  • 即使外部函数已返回,当前函数仍然能使用外部函数定义的变量
//闭包比创建它们的函数有更长的生命周期
function makeSandwich(){
    var magicIngredient="peanuts butter";
    function make(filling){
        return magicIngredient+ " and "+filling;
    }
    return make;
}
//或者
function makeSandwich(){
    var magicIngredient="peanuts butter";   
    return function make(filling){
        return magicIngredient+ " and "+filling;
    };
}

var f = makeSandwich();
f("apple");//"peanuts butter and apple"
f("bananas");//"peanuts butter and bananas"

解释:JS的函数值包含了比调用它们时执行所需要的代码还要多的信息,它们在内部存储着可能会引用的定义在封闭作用域的变量。

  • 闭包可以更新外部变量的值
    闭包实际存储的是对外部变量的引用,而不是它们的副本,因此可以对其进行更新
//函数在内部存储其外部变量的引用,并能读写这些变量
//2D storage.js
var wrapStorage = function () {
    lo = {};
    return {
        get: function (attr) {
            return lo[attr];
        },
        set: function (attr, val) {
            lo[attr] = val;
            return this;
        },
        remove: function (attr) {
            delete lo[attr];
            return this;
        }
        size: function () {
            return Object.keys(lo).length;
        },
        toJSON: function () {
            var o = {}, i;
            for (i in lo) {
                o[i] = lo[i];
            }
            return o;
        },
        toString: function () {
            return JSON.stringify(lo);
        }
    };
};

var jsonObject=wrapStorage("name");
jsonObject.get(1);//undefined
jsonObject.set(1,"haha");//undefined
jsonObject.get(1);//"haha"

变量声明提升

函数内部的变量只有函数级作用域,没有块级作用域;
理解变量提升:变量的声明与赋值是分开的,当用var 声明并赋值一个变量时,JS隐式的将变量的声明提升到函数的顶部,并赋值留在原处;

使用立即调用函数创建局部作用域

//在运行时进入作用域,JS会为每个在作用域内的变量分配一个"slot"
function wrapElements(a){
    var i,result = [];  //分配了两个"slot"
    for(i=0;i<a.length;i++){
        result[i]=function(){  //闭包存储的是对外部变量i的引用而不是i的值,因此每个闭包其实都引用一个共享的"slot",即5(i的值最后为5)
            return a[i]; 
        } 
    }
    return result;
}

var wrapped=wrapElements([1,2,3,4,5]);
var f=wrapped[0];
f();//undefined

//解决办法:创建一个嵌套函数并立即调用来创建一个局部作用域
function wrapElements(a){
    var i,result = [];
    for(i=0;i<a.length;i++){
        (function(j){
            result[i]=function(){
                return a[j]; 
        }
        })(i);//每次执行都会创建一个新的"slot"   
    }
    return result;
}

var wrapped=wrapElements([1,2,3,4,5]);
var f=wrapped[0];
f();//1

call:使用call来自定义接收者来调用方法

  • 自定义接收者来调用函数,原始方法
obj.temporary=f;
var result=obj.temporary(arg1,arg2,arg3);
delete obj.temporary;

缺点:代码复杂,而且通常情况下不应该修改obj对象;

  • call方法
f.call(obj,arg1,arg2,arg3); //obj即为接收者对象

//实例
var dict={};
dict.foo=1;
var f=function(arg){
    return arg?arg:this.foo;  //执行call时,this就是dict对象
};
f.call(dict);//1
  • 总结:
    • 使用call方法来自定义接收者来调用方法;
    • 使用call方法可以调用在给定对象中不存在的方法(继承);

apply:使用apply通过不同数量的参数调用函数

//apply方法与call方法作用一样,但是apply方法的第二个参数是一个数组
f.apply(obj,[arg1,arg2,arg3]); 

arguments

  • JS给每个函数都隐式的提供了一个arguments变量,arguments对象有一个length属性来指示参数的个数
  • 永远不要修改arguments对象
//arguments对象不是函数参数的副本,而且所有命名参数都是arguments对象中对应索引的别名。
function callMethod(obj,method){
    Array.prototype.shift.call(arguments);
    Array.prototype.shift.call(arguments);//即使删除元素,obj仍然为arguments[0]的别名;method仍为arguments[1]的别名;
    return obj[method].apply(obj,arguments);//因此此时,method==arguments[0]==3,obj==arguments[1]==4,
}
var obj={add:function(x,y){return x+y ;}};
callMethod(obj,"method",3,4);
//非严格模式下
function nonstrict(x){
    arguments[0]="123";
    console.log("x = "+x); //x="123"
    console.log("arguments[0] = "+arguments[0]); //arguments[0]="123"
    return x===arguments[0]; //true
}
nonstrict("456");

//严格模式下
function strict(x){
    "use strict";
    arguments[0]="123";
    console.log("x = "+x);//x="456"
    console.log("arguments[0] = "+arguments[0]);//arguments[0]="123"
    return x===arguments[0];//false
}
  • var args = Array.prototype.slice.call(arguments)将arguments对象复制到一个真正的数组中再进行操作

    数组方法
  • concat : //叠加数组
var color=["red","green","blue"];
var tempColor=color.concat("yellow",["black,white"]);
alert(color); //["red","green","blue"];
alert(tempColor);//["red","green","blue","yellow","black","white"];

//如果concat或slice后面的参数为空,则相当于复制了一个副本到新的数组
  • slice : 提取数组
var color=["red","green","blue","yellow"];
var color2=color.slice(1); //["green","blue","yellow"]
var color3=color.slice(1,3); //["green","blue"]
  • splice
var color=["red","green","blue"];
//删除:两个参数,要删除的第一项的位置,要删除的项数
var removed=color.splice(0,1); //从位置1开始删除一项
alert(color); //["green","blue"]
alert(removed); //["red"]

//插入:要插入的位置,要删除的项数,要插入的项
removed=color.splice(1,0,"white","black");//从位置1插入两项
alert(color); //["green","white","black","blue"]
alert(removed); //空数组

//替换:要插入的位置,要删除的项数,要插入的项
removed=color.splice(1,1,"red","yellow");//从位置1开始删除一项并插入两项
alert(color); //["green","red","yellow","black","blue"]
alert(removed); //["white"]
  • every,some,filter,forEach,map
//函数不支持breakcontinue,如果需要调到下一个循环则用return,无法退出循环
/*every:每一项都返回true才返回true;
some:只要有一项返回true就返回true;
filter:对数组中的每一项都运行函数,返回该函数会返回true的项组成的数组;
map:对数组中的每一项都运行函数,返回该函数调用结果组成的数组;*/

原型

每个函数都有一个prototype属性,这个属性是一个指针,指向一个(原型)对象,这个对象的用途是包含所有实例共享的属性和方法

原型对象

所有原型对象都会获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针:

function person(){};
person.prototype.constructor===person; //true

当用构造函数创建一个实例的时候,这个实例将包含一个属性,它是一个指向构造函数的原型对象的指针。

var man=new person();
man.constructor===person; //true
man.__proto__===person.prototype; //true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
☆ 资源说明:☆ [Addison-Wesley Professional] Effective JavaScript 编写高质量JavaScript代码的68个有效方法 (英文版) [Addison-Wesley Professional] Effective JavaScript 68 Specific Ways to Harness the Power of JavaScript (E-Book) ☆ 图书概要:☆ In order to truly master JavaScript, you need to learn how to work effectively with the language’s flexible, expressive features and how to avoid its pitfalls. No matter how long you’ve been writing JavaScript code, Effective JavaScript will help deepen your understanding of this powerful language, so you can build more predictable, reliable, and maintainable programs. Author David Herman, with his years of experience on Ecma’s JavaScript standardization committee, illuminates the language’s inner workings as never before—helping you take full advantage of JavaScript’s expressiveness. Reflecting the latest versions of the JavaScript standard, the book offers well-proven techniques and best practices you’ll rely on for years to come. Effective JavaScript is organized around 68 proven approaches for writing better JavaScript, backed by concrete examples. You’ll learn how to choose the right programming style for each project, manage unanticipated problems, and work more successfully with every facet of JavaScript programming from data structures to concurrency. ☆ 出版信息:☆ [作者信息] David Herman [出版机构] Addison-Wesley Professional [出版日期] 2012年12月06日 [图书页数] 240页 [图书语言] 英语 [图书格式] PDF 格式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值