JS重要知识点

这里列出了一些JS重要知识点(不全面,但自己感觉很重要)。彻底理解并掌握这些知识点,对于每个想要深入学习JS的朋友应该都是必须的。

讲解还是以示例代码搭配注释的形式,这里做个小目录:

JS代码预解析原理(包括三个段落);

函数相关(包括 函数传参,带参数函数的调用方式,闭包);

面向对象(包括 对象创建、原型链,数据类型的检测,继承)。

JS代码预解析原理

/****************** JS代码预解析原理 ******************/
/*
JS代码预解析、变量作用域、作用域链等 应该能作为学习JS语言的入门必备知识。
下边给出些简要解释和一些典型的代码段,若要了解更多,能从网上搜索到更多相关示例。

引用网上的一段有关 “JS的执行顺序” 的解释:
如果一个文档流中包含多个script代码段(用script标签分隔的js代码或引入的js文件),它们的运行顺序是:
步骤1. 读入第一个代码段(js执行引擎并非一行一行地执行程序,而是一段一段地分析执行的)
步骤2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到步骤5
步骤3. 对var变量和function定义做“预解析”(永远不会报错的,因为只解析正确的声明)
步骤4. 执行代码段,有错则报错(比如变量未定义)
步骤5. 如果还有下一个代码段,则读入下一个代码段,重复步骤2
步骤6. 结束
*/
// 下边给出 三段觉得比较典型的代码示例:
/********** 一:基本的几条语句 **********/
alert(num);  // undefined
var num = 0;
alert(str);  // 错误:str未定义
str = "string";
alert(func);  // undefined
var func = function (){ alert(‘exec func‘); }
test();  // exec test
alert(test());  // 先exec test 后undefined
function test(){ alert(‘exec test‘); }

/********** 二:函数名与变量名相同 **********/
//var mark = 1;
function mark(x) {
  return x * 2;
}
var mark;
alert(mark);  // function mark(x) {   return x * 2; }
// 去掉前边的var mark = 1;则会返回1

/********** 三:把第二段包括在语句块中 **********/
// 当有条件时候(代码包含在条件语句块里)
if (false) {
    var mark1 = 1;
    function mark1() {
       alert("exec mark1");
    }
    //var mark1;
    alert(mark1);
}
alert(mark1);
mark1();
// 由于解析浏览器解析不同,这段代码在不同浏览器里执行的结果不一致,具体原因可从网上查找答案

  函数相关(包括 函数传参,带参数函数的调用方式,闭包)

/****************** 函数相关 ******************/

/********** 一:函数传参 **********/
/*
编程语言大概都有 值类型与引用类型 的区别,JS也不例外。
原始类型:undefined  null number boolean 均为值类型。
string比较特殊,因为它是不可改变的,String类定义的方法都不能改变字符串的内容。
function object array 这三种为引用类型。
*/
/* JavaScript 函数传递参数时,是值传递。

ECMAScript 中,所有函数的参数都是按值来传递的。
基本类型值的传递和基本类型变量复制一致(采用在栈内新建值),
引用类型值的传递和引用类型变量的复制一致(栈内存放的是指针,指向堆中同一对象)。
具体参考:http://www.xiaoxiaozi.com/2010/03/05/1719/
*/
function setName(obj){
    //obj拷贝了person的值(person是一个对象的引用地址),所以obj也指向了person所指向的对象。
    obj.name = "xiaoxiaozi";
    obj = {}; // 让obj 指向了另一个对象
    obj.name = "admin";
}
var person = {};
setName(person);
alert(person.name); //  xiaoxiaozi

/********** 二:带参数函数的调用方式 **********/
/* 在DOM不同版本中,函数调用方式不太一样。标准推荐的是addEventListener和attachEvent
    这两种方式有很多资料可查。但是有些已经不被推荐的函数调用仍旧有实际应用,相关资料发现的不多。
    这里主要讨论这些函数调用方式
*/
var g = "全局变量";
function show(str) {
    alert("my site: " + str);
}
setTimeout("show(g);",100);  // g是全局变量,函数正确执行
function t() {
    var url = "www.xujiwei.cn";
    var num = 2;
    //setTimeout("alert("+url+")", 3000);    //   解析错误,www未定义
    //setTimeout("alert("+num+")", 3000);    //   解析正确,注意与上句对比
    //setTimeout("show(‘url‘);", 2000);    //   url
    //setTimeout("show("+ url +");", 2000);    //   解析错误,www未定义
    //setTimeout("show(url);", 2000);    //   解析错误,url未定义
    //setTimeout(‘"show("+ url +");"‘, 2000);    //   解析错误,url未定义
    //setTimeout("show(‘"+ url +"‘);", 2000);    // 正确
    //setTimeout(function(){show(url);},1000);   // 正确
}
t();
/* 结论:
    诸如onclick="xx();"等函数调用方式,在双引号内的内容直接解析为js语句执行。
    若调用的函数带有参数,注意对比以上各种写法,保证传递进去的参数为正确的。
*/        

/********** 三:闭包 **********/
/*
闭包,几乎是每个学习JS的朋友都要讨论的问题,因此各种相关资料应有尽有。
它的作用很大,但也有弊端,例如如果使用不当,容易引起内存泄漏等问题,因此有不少人
提倡少用闭包。

这里列出闭包的一种经典应用,一个有争议的应用。
*/
function test1() {     //通过闭包,每次能传入不同的j值。
    for (var j = 0; j < 3; j++) {
        (function (j) {
            setTimeout(function () { alert(j) }, 3000);
        })(j);
    }
}
test1();
/* 这个是闭包的典型应用 */

(function tt() {
    for (var i = 1; i < 4; i++) {
        document.getElementById("b" + i).attachEvent("onclick",
        new Function(‘alert("This is button‘ + i + ‘");‘)); // 在IE中测试
    }
})()  // 立即执行函数,一个文件是否只能有一个?把上边函数写成立即执行出问题,怎么回事?

/* 这个问题出现在论坛里,有很多争议
有说是new Function动态生成个闭包结构的函数,所以能保存外部变量。
有说是跟闭包无关,new Function,就是新定义了一个function,
i的值也作为这个新的function的参数固化在其内部了。
*/

  面向对象(包括 对象创建、原型链,数据类型的检测,继承)

/****************** 面向对象 ******************/

/********** 一:对象创建、原型链 **********/
/* 讨论 构造函数(类方式)创建对象 ,深入理解这些内容,是很重要的
*/
function MyFunc() { }; //定义一个空函数
var anObj = new MyFunc(); //使用new操作符,借助MyFun函数,就创建了一个对象
// 等价于:
function MyFunc() { };
var anObj = {};     //创建一个对象
anObj.__proto__ = MyFunc.prototype;
MyFunc.call(anObj); //将anObj对象作为this指针调用MyFunc函数
/*
用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:
第一步:建立一个新对象(anObject);
第二步:将该对象内置的原型对象(__proto__)设置为构造函数prototype引用的那个原型对象;
第三步:将该对象作为this参数调用构造函数,完成成员设置等初始化工作。

对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象有关,
与构造函数再扯不上关系了。
换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。

原型链:(参考:http://hi.baidu.com/fegro/blog/item/41ec7ca70cdb98e59152eed0.html)
    每个对象(此处对象应该仅指大括号括起来的object,不包括function、array。待验证?)
    都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性时,
    如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,
    这个__proto__又会有自己的__proto__,于是就这样 一直找下去,也就是我们平时所说的原型链的概念。
*/ 

/* 理解了对象创建的原理,可试着分析下边两个示例的结果 */
var yx01 = new function() {return "圆心"};
alert(yx01); // [object Object]
var yx02 = new function() {return new String("圆心")};
alert(yx02); // “圆心”
/* 解释:
"圆心"是基本的字符串类型,new String("圆心")则创建了一个string对象。
只要new表达式之后的构造函数返回一个引用对象(数组,对象,函数等),都将覆盖new创建的对象,
如果返回一个原始类型(无 return 时其实为 return 原始类型 undefined),
那么就返回 new 创建的对象。
参考:http://www.planabc.net/2008/02/20/javascript_new_function/
*/

/********** 二:数据类型的检测 **********/
/* 判断数据类型可能想到的方法:
constructor、typeof、instanceof、Object.prototype.toString.call()
*/
/***** 1、通过constructor属性  *****/
var myvar= new Array("a","b","c","d");
function A(){}
myvar.constructor = A;
var c = myvar.constructor;
alert(c); // function A(){}
//可见,通过constructor属性获取类型的方法很容易被修改,不应该用来判断类型。

/***** 2、通过typeof  *****/
/*
    typeof是一个操作符,而不是个函数。
    typeof的实际应用是用来检测一个对象是否已经定义或者是否已经赋值。
        如if(typeof a!="undefined"){},而不要去使用if(a)因为如果a不存在(未声明)则会出错。
    typeof检测对象类型时一般只能返回如下几个结果:
    number,boolean,string,function,object,undefined。
    对于Array,Null,自定义对象 等使用typeof一律返回object,
        这正是typeof的局限性。
*/
var num = new Number(1);
var arr = [1,2,3];
alert(typeof num);  //object 而不是number
alert(typeof arr);  //object 而不是Array
alert(typeof null);  // object

/***** 3、通过 instanceof  *****/
/* 用instanceof操作符来判断对象是否是某个类的实例。
    如果obj instanceof Class返回true,那么Class的原型与obj原型链上的某个原型是同一个对象,
    即obj要么由Class创建,要么由Class的子类创建。
*/
function t(){};
t.prototype  = Array.prototype;
//t.prototype  = [];
var x = new t();
alert(x instanceof t);//弹出true
alert(x instanceof Array);//弹出true
alert(x instanceof Object);//弹出true
/*
由此可知,通过 instanceof 判断数据类型也不可靠。
因为一个对象(此处x)的原型链可以很长,每个原型的类型可以不同。

另外在iframe内也会容易出错:
即有个页面定义了一个数组a,页面又嵌套了一个IFrame,在Iframe里面通过 top.a instanceof Array, 是返回false的。
这个说明 父页面和内嵌iframe里的对象是不同的,不能混合在一起使用。
改成top.a instanceof top.Array 就会返回true
*/

/***** 4、通过 Object.prototype.toString.call()  *****/
/*
Object.prototype.toString.call() 作用是:
    1、获取对象的类名(对象类型)。
    2、然后将[object、获取的类名]组合并返回。
可应用于判断Array,Date,Function等类型的对象
*/
var num = new Number(1);
var arr = [1,2,3];
alert(Object.prototype.toString.call(num)); // [object Number]
alert(Object.prototype.toString.call(arr)); // [object Array]

// 扩展示例:(apply等价于call)
window.utils = {
    toString: Object.prototype.toString,
    isObject: function (obj) {
        return this.toString.apply(obj) === ‘[object Object]‘;
    },
    isFunction: function (obj) {
        return this.toString.apply(obj) === ‘[object Function]‘;
    },
    isArray: function (obj) {
        return this.toString.apply(obj) === ‘[object Array]‘;
    }
}
function A() { }
window.utils.isFunction(A);        //true
window.utils.isObject(new A());    //true
window.utils.isArray([]);          //true

/*
jQuery等框架 就是用这个方法判断对象的类型的,因此可以把这种方法作为权威的判断方法。
但是,如果重写了Object.prototype.toString方法,这时候再用来判断数据类型可能就会出错,
所以,一般不要去重写Object.prototype.toString方法。
*/

/********** 三:继承 **********/
/*
JS继承和闭包一样,几乎是每个想深入学习JS的朋友都要讨论的问题,因此各种相关资料应有尽有。
JS继承代码的版本非常多,但原理都是一样的,核心都是利用了prototype对象。
为了和其他面向对象语言的风格相似,大多数都采用“类式”风格模拟。

继承的详细原理不再赘述,网上有许多资料介绍。
这里给出一个示例:Jquery作者John Resig写的继承。
(其中的详细注释是来自某个博客,不知道是谁原创,这里私自转帖出来)
*/
(function () {
// initializing变量用来标示当前是否处于类的创建阶段,
// - 在类的创建阶段是不能调用原型方法init的
// - 我们曾在本系列的第三篇文章中详细阐述了这个问题
// fnTest是一个正则表达式,可能的取值为(/\b_super\b/ 或 /.*/)
// - 对 /xyz/.test(function() { xyz; }) 的测试是为了检测浏览器是否支持test参数为函数的情况
// - 不过我对IE7.0,Chrome2.0,FF3.5进行了测试,此测试都返回true。
// - 所以我想这样对fnTest赋值大部分情况下也是对的:fnTest = /\b_super\b/;
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
// 基类构造函数
// 这里的this是window,所以这整段代码就向外界开辟了一扇窗户 - window.Class
this.Class = function () { };
// 继承方法定义
Class.extend = function (prop) {
    // 这个地方很是迷惑人,还记得我在本系列的第二篇文章中提到的么
    // - this具体指向什么不是定义时能决定的,而是要看此函数是怎么被调用的
    // - 我们已经知道extend肯定是作为方法调用的,而不是作为构造函数
    // - 所以这里this指向的不是Object,而是Function(即是Class),那么this.prototype就是父类的原型对象
    // - 注意:_super指向父类的原型对象,我们会在后面的代码中多次碰见这个变量
    var _super = this.prototype;
    // 通过将子类的原型指向父类的一个实例对象来完成继承
    // - 注意:this是基类构造函数(即是Class)
    initializing = true;
    var prototype = new this();
    initializing = false;
    // 我觉得这段代码是经过作者优化过的,所以读起来非常生硬,我会在后面详解
    for (var name in prop) {
        prototype[name] = typeof prop[name] == "function" &&
                typeof _super[name] == "function" && fnTest.test(prop[name]) ?
                (function (name, fn) {
                    return function () {
                        var tmp = this._super; // 这里是必要的,第91行注释代码可说明之。
                        this._super = _super[name];
                        var ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(name, prop[name]) :
                prop[name];
    }
    // 这个地方可以看出,Resig很会伪装哦
    // - 使用一个同名的局部变量来覆盖全局变量,很是迷惑人
    // - 如果你觉得拗口的话,完全可以使用另外一个名字,比如function F()来代替function Class()
    // - 注意:这里的Class不是在最外层定义的那个基类构造函数
    // 这里的Class和上边的window.Class函数不一样,这里是window.Class内部的函数局部变量
    function Class() {
        // 在类的实例化时,调用原型方法init
        if (!initializing && this.init)
            this.init.apply(this, arguments);
    }
    // 子类的prototype指向父类的实例(完成继承的关键)
    Class.prototype = prototype;  // Class指代上边的Class,并非一开始的window.Class
    // 修正constructor指向错误
    // 是否可用Class.prototype.constructor = Class;来修正???
    Class.constructor = Class;
    // 子类自动获取extend方法,arguments.callee指向当前正在执行的函数
    Class.extend = arguments.callee;
    return Class;
};
})();

  http://www.cnblogs.com/huajs/archive/2011/11/05/2237091.html

时间: 2024-11-01 05:31:30

JS重要知识点的相关文章

js基础知识点收集

js基础知识点收集 js常用基本类型 function show(x) { console.log(typeof(x)); // undefined console.log(typeof(10)); // number console.log(typeof('abc')); // string console.log(typeof(true)); // boolean console.log(typeof([])); // object console.log(typeof(function (

js基础知识点总结

js基础知识点总结 如何在一个网站或者一个页面,去书写你的js代码:1.js的分层(功能):jquery(tool) 组件(ui) 应用(app),mvc(backboneJs)2.js的规划():避免全局变量和方法(命名空间,闭包,面向对象),模块化(seaJs,requireJs) 常用内部类:Data Array Math String HTML属性,CSS属性HTML:属性.HTML属性="值":CSS:对象.style.CSS属性="值"; class和f

Node.js的知识点框架整理

背景:因为appium是基于Node.js的,所以想看一下Node.js.但是发现很多资料的顺序看起来有点颠倒.然后就一面看资料一面整理了一下大概的知识点框架,希望对自己对别人有用. 本文不包含node.js的基本语法.node.js的基本语法和JavaScript基本一样,可以以后再单独整理一份基本语法的. Node.js是一个基于chrome V8的JavaScript运行时的环境 Node.js是事件驱动,非阻塞式I/O模型 Node.js使用npm包管理器 使用Node.js不仅实现了一

11、网页制作Dreamweaver(补充:JS零碎知识点&amp;&amp;正则表达式)

JS知识点 回车符/r和换行符/n的区别:/r 相当于enter,是段落与段落之间的区别, /n 相当于shift+enter,是行与行之间距离,比较小 几种window操作方法: 1.获取当前窗口大小并打印: var height=window.innerHeight; var width = window.innerWidth; document.write("<br/>"+"height"+height+","+"wi

js 面试知识点

基础           原型  原型链 作用域  闭包 异步  单线程 JS API        DOM操作 AJAX 事件绑定 开发环境    版本管理 模块化 打包工具 运行环境    页面渲染 性能优化 面试题 1.JS中使用 typeof 能得到的哪些类型? 考点:JS变量类型 JS中有哪些内置函数 JS变量按照存储方式区分为哪些类型,并描述其特点 值类型      内存地址 不会因为赋值而相互干预 引用类型   指针  节省内存空间   可以无限制扩展属性 如何理解JSON 知识点

Node.js前置知识点(一):回调函数

前言 因为开始了解和学习Node.js,发现在使用之前,有必要先知道一些前置的知识点(其实是关于操作系统的知识),主要包括: 什么是 回调函数(callback): 什么是 同步/异步: 什么是 I/O: 什么是 单线程/多线程: 什么是 阻塞/非阻塞: 什么是 事件 和 事件驱动: 什么是 基于事件驱动的 回调: 什么是 事件循环: 本文就是系列文章的第一篇,用来介绍回调函数.(参考来源 见文末的 Reference) 一 什么是 回调函数(callback) 我觉得理解一个概念,应该是从简单

JS函数知识点梳理

要想学好JavaScript除了基本的JavaScript知识点外,作为JavaScript的第一等公民--函数,我们要深入的了解.函数的多变来源于参数的灵活多变和返回值的多变.如果参数是一般的数据类型或一般对象,这样的函数就是普通函数:如果函数的参数是函数,这就是我们所要知道的高级函数:如果创建的函数调用另外一部分(变量和参数已经预置),这样的函数就是偏函数. 此外,还有一点就是可选参数(optional parameter)的使用. 函数的分类 普通函数 有函数名,参数,返回值,同名覆盖.示

【干货】JS相关知识点总结

一.获取元素方法 可以使用内置对象document上的getElementById方法来获取页面上设置了id属性的元素,获取到的是一个html对象,然后将它赋值给一个变量.如下: 上面的语句,如果把javascript写在元素的上面,就会出错,因为页面是从上往下加载执行的,javascript去页面上获取元素div1的时候,元素div1还没有加载,解决方法有两种 二.操作元素属性 1.获取页面的元素,就可以对页面元素的属性进行操作,属性的操作包括属性的读和写. 操作属性的方法:a."."

js常见知识点3.面向对象之继承、设计模式

一.面向对象的三大特征 建议回复: 封装:屏蔽内部细节.调用外部接口实现对应功能(函数调用) 继承:子类继承父类中的属性和方法 多态(js中不存在多态的概念) 二.继承 建议回复: 继承:子类继承父类中的属性和方法 , 这些属性和方法在子类中不需要实现过程 继承的种类:  单继承:一个子类只拥有一个父类 多继承:一个子类可以拥有多个父类 三.继承的方式及实现过程 建议回复: 1.继承方式一.通过改变构造函数(父类)的执行环境 ---在子类中添加一个特殊属性,这个属性值指向父类