目的

  记录一下学习心得,便于以后复习,内容是比较基础的...但是很多内容我还是不知道...

对象

对象使用和属性

1.JavaScript 中所有变量都可以当作对象使用,除了两个例外 null和dundefined。

数字其实也可以当做对象,只是因为.会被当成小数点,所以要这么写(2).toString(),即下一个括号

2.删除属性的唯一方法是使用 delete 操作符

所以delete操作符是有用的,只有用了delete以后in操作才会返回false

原型

1.当原型属性用来创建原型链时,可以把任何类型的值赋给它(prototype)。 然而将原子类型赋给 prototype 的操作将会被忽略。

所以说

 function Foo() {} Foo.prototype = new String();
function Foo() {} Foo.prototype = '';

是不同的,下面那种操作会被忽略

hasOwnProperty 函数

1.hasOwnProperty 是 JavaScript 中唯一一个处理属性但是查找原型链的函数。

 // 修改Object.prototype
Object.prototype.bar = 1;
var foo = {goo: undefined}; foo.bar; //
'bar' in foo; // true foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true

for in 循环

1.和 in 操作符一样,for in 循环同样在查找对象属性时遍历原型链上的所有属性。

如果要找出对象自己定义的属性.可以配合使用hasOwnProperty

 // foo 变量是上例中的
for(var i in foo) {
if (foo.hasOwnProperty(i)) {
console.log(i);
}
}

函数

this 的工作原理

1.当在全部范围内使用 this,它将会指向全局对象。浏览器里是window

函数调用foo();的时候相当于是window.foo(),所以也是window

test.foo();的时候是test

构造方法 new Foo()的时候是指向创建的对象

不过this和java里不一样,java里的时候编译的时候就能知道this指向哪个对象,但是js不行,因为即使在调用的时候也可以改变this.

比如:

 function foo(a) {this.a = a}
var bar = {};
foo.apply(bar, [1]); // bar.a = 1
foo.call(bar, 1); // bar.a = 1

这也是call和apply的使用场景吧,改变this指向

2.直接调用方法的时候即使是在其他函数内部this也是指向全局对象window

 Foo.method = function() {
function test() {
// this 将会被设置为全局对象
}
test();
}

不过一般在这里不会使用this,因为没啥用处

3.方法别名的时候this可能也会被改变

 var test = someObject.methodTest;
test();//test内this指向window

闭包和引用

1.

 for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}

上面的代码不会输出数字 0 到 9,而是会输出数字 10 十次。

当 console.log 被调用的时候,匿名函数保持对外部变量 i 的引用,此时for循环已经结束, i 的值被修改成了 10.

然后timeout时间到了调用匿名函数的时候会访问那个i,所以会输出10次10

解决办法:

 for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
} //或者 for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}

原理都差不多,就是通过匿名自执行函数,把数据当做函数形参传入函数内部,这样就有了1份拷贝.

arguments 对象

1.使用 call 和 apply,创建一个快速的解绑定包装器。(??)

 function Foo() {}

 Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
}; // 创建一个解绑定的 "method"
// 输入参数为: this, arg1, arg2...argN
Foo.method = function() { // 结果: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};

这里prototype上面的方法很想java里的父类的成员方法,而Foo.method很像java里类的静态方法.

这里之所以能使用Foo.method为对象设值,就是因为this可以动态的改变指向.

但是有几个地方我一直搞不懂.....

Function.call.apply === Function.apply === Foo.method.apply

为何替换Function.call.apply为Function.apply会报错?

而且一般都是这么用的吧:

 Foo.method = function() {
var args = Array.prototype.slice.call(arguments);
Foo.prototype.method.apply(args[0], args.slice(1));
};

apply的第一个参数是this的指向..但是调用Function.call.apply的时候却传入了一个方法..而Function.call.apply又等价于Foo.method.apply ....很奇怪..不过Foo.call.apply是显示native code,不知道是不是有什么特殊的地方.

2.有一种情况会显著的影响现代 JavaScript 引擎的性能。这就是使用 arguments.callee。(??)

 function foo() {
arguments.callee; // do something with this function object
arguments.callee.caller; // and the calling function object
} function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // Would normally be inlined...
}
}

上面代码中,foo 不再是一个单纯的内联函数 inlining译者注:这里指的是解析器可以做内联处理), 因为它需要知道它自己和它的调用者。 这不仅抵消了内联函数带来的性能提升,而且破坏了封装,因此现在函数可能要依赖于特定的上下文。

因此强烈建议大家不要使用 arguments.callee 和它的属性。

arguments.callee不知道有和用处,因为在函数内部应该能够知道自己叫什么名字吧...不过arguments.callee.caller能够在运行期获取调用它的函数,这个似乎有点用处,与java里的反射有点像(只是一点点..)

不知道实际生产中有什么通途..

构造方法

1.显式的 return 表达式将会影响返回结果,但仅限于返回的是一个对象。

 function Bar() {
return 2;
}
new Bar(); // 返回新创建的对象 Bar {} function Test() {
this.value = 2; return {
foo: 1
};
}
new Test(); // 返回的对象 Object {foo: 1}

但是因为return返回了字面值对象,所以这个对象的原型并不是指向构造方法的prototype. 比如

 function Test() {
this.value = 2; return {
foo: 1
};
}
Test.prototype.bar = 2
new Test(); //Object {foo: 1} 而不是 Test{....}

2.通过工厂模式创建对象

 function Foo() {
var obj = {};
obj.value = 'blub'; var private = 2;
obj.someMethod = function(value) {
this.value = value;
} obj.getPrivate = function() {
return private;
}
return obj;
}

坏处就是没有用到原型链,所有东西都不是共享的.

作用域与命名空间

1.javascript没有块级作用域,比如说for的{}

2.变量声明提升(Hoisting): JavaScript 会提升变量声明。这意味着 var 表达式和 function 声明都将会被提升到当前作用域的顶部。

 bar();
var bar = function() {};
var someValue = 42; test();
function test(data) {
if (false) {
goo = 1; } else {
var goo = 2;
}
for(var i = 0; i < 100; i++) {
var e = data[i];
}
} //等价于 // var 表达式被移动到这里
var bar, someValue; // 缺省值是 'undefined' // 函数声明也会提升
function test(data) {
var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部
if (false) {
goo = 1; } else {
goo = 2;
}
for(i = 0; i < 100; i++) {
e = data[i];
}
} bar(); // 出错:TypeError,因为 bar 依然是 'undefined'
someValue = 42; // 赋值语句不会被提升规则(hoisting)影响
bar = function() {}; test();
 // 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则
var myvar = 'my value'; (function() {
alert(myvar); // undefined
var myvar = 'local value';
})();

这段代码没有输出全局变量的值而是输出了undefined,这正是因为变量声明的提升的结果,也就是说后面的声明var myvar被提升到了方法最顶部.

3.匿名自执行函数的写法:

 (function() {
// 函数创建一个命名空间 window.foo = function() {
// 对外公开的函数,创建了闭包
}; })(); // 立即执行此匿名函数 // 另外两种方式
+function(){}();
(function(){}());

数组

数组便利与属性

1.只有显式设置了数组的值,用in才会返回true

 var foo = [];
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 false
foo[5] = undefined;
5 in foo; // 不管在 Firebug 或者 Chrome 都返回 true
1 in foo; //false

Array 构造函数

1.推荐使用字面值[]来创建数组,而不是构造方法,因为构造方法有点模棱两可.

 [1, 2, 3]; // 结果: [1, 2, 3]
new Array(1, 2, 3); // 结果: [1, 2, 3] [3]; // 结果: [3]
new Array(3); // 结果: []
new Array('3') // 结果: ['3'] // 译者注:因此下面的代码将会使人很迷惑
new Array(3, 4, 5); // 结果: [3, 4, 5]
new Array(3) // 结果: [],此数组长度为 3

另外和前面类似,只有显示设置了值,in才会返回true

 var arr = new Array(3);//虽然创建了数组,console里打印显示[undefined X 3],但是其实并未设置值
arr[1]; // undefined
1 in arr; // false, 数组还没有生成
arr[1] = undefined;
1 in arr; // true

类型

相等与比较

1. ==比较对象是不方便的,因为可能会发生类型转化,可以使用===代替

 ""           ==   "0"           // false
0 == "" // true
0 == "0" // true
false == "false" // false
false == "0" // true
false == undefined // false
false == null // false
null == undefined // true
" \t\r\n" == 0 // true "" === "0" // false
0 === "" // false
0 === "0" // false
false === "false" // false
false === "0" // false
false === undefined // false
false === null // false
null === undefined // false
" \t\r\n" === 0 // false

typeof 操作符

1.typeof关键字实际中只有1个用途,用来判断对象是不是有定义.而不是用来检查对象的类型,因为几乎不可能从它们那里得到想要的结果。

绝大部分返回结果都是object

 Value               Class      Type
-------------------------------------
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object

class的值可以通过调用Object.prototype.toString并改变this来获得.

 function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== undefined && obj !== null && clas === type;
} is('String', 'test'); // true
is('String', new String('test')); // true

实际上我感觉也没啥用处.因为自己写的对象是什么类型肯定清楚,而给别人提供API的时候别人传错类型那报错很正常,好像也没啥比要专门去检查..不过这也是一种判断类型的方法把.不过这个class不能用于判断自定义对象,因为会返回Object

instanceof 操作符

1.从instanceof操作符可以看出javascript就是通过原型链来实现继承的

 function Foo() {}
function Bar() {}
Bar.prototype = new Foo(); new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true // 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
Bar.prototype = Foo;
new Bar() instanceof Foo; // false
new Bar() instanceof Function; // true

2.instanceof 比较自定义对象还是很方便的,但是比较内置对象比较坑爹

 new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true 'foo' instanceof String; // false
'foo' instanceof Object; // false

类型转换

1.==比较对象会发生类型转化

 var a = {
toString : function(){
return '123';
}
}
a == '123'; //true var a = {
toString : function(){
return '123';
},
valueOf : function(){
return '456';
}
}
a == '123'; //false
a == '456'; //true

对象比较的时候会先调用toString方法转化成字符串,但是如果有valueOf方法的话会用valueOf代替toString()方法

2.其他一些转化

 // 下面的比较结果是:true
new Number(10) == 10; // Number.toString() 返回的字符串被再次转换为数字 10 == '10'; // 字符串被转换为数字
10 == '+10 '; // 同上
10 == '010'; // 同上
isNaN(null) == false; // null 被转换为数字 0
// 0 当然不是一个 NaN(译者注:否定之否定) // 下面的比较结果是:false
10 == 010;
10 == '-10';

3.对象在比较的时候可能都转化成一种类型再进行比较会比较清楚明晰

转化成String可以用空字符串加上其他变量: '' + {}

转化成数字可以使用一元运算符加号: + '10'

转化成布尔值可以使用叹号: !!{}

核心

为什么不要使用 eval

1.eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。

 var foo = 1;
function test() {
var foo = 2;
eval('foo = 3');
return foo;
}
test(); //
foo; // var foo = 1;
function test() {
var foo = 2;
var bar = eval;
bar('foo = 3');
return foo;
}
test(); //
foo; //

undefined 和 null

1.undefined的值是可以被被修改的,所以在jquery源码的时候看到会用到下面这样的写法保证undefined就是undefined

 var undefined = 123;
(function(something, foo, undefined) {
// 局部作用域里的 undefined 变量重新获得了 `undefined` 值 })('Hello World', 42); //或者 var undefined = 123;
(function(something, foo) {
var undefined;
... })('Hello World', 42);

在看miniui压缩过的代码的时候我发现有个一元运算符void也可以返回undefined.

 void 0 === undefined; //true

其它

setTimeout 和 setInterval

1.setTimeout方法作为第一个参数的函数将会在全局作用域中执行,因此函数内的 this 将会指向这个全局对象。

 function Foo() {
this.value = 42;
this.method = function() {
// this 指向全局对象
console.log(this.value); // 输出:undefined
};
setTimeout(this.method, 500);
}
new Foo();

2.setInterval 的堆调用(??):

当回调函数的执行被阻塞时,setInterval 仍然会发布更多的回调指令。在很小的定时间隔情况下,这会导致回调函数被堆积起来。

 function foo(){
// 阻塞执行 1 秒
}
setInterval(foo, 100);

上面代码中,foo 会执行一次随后被阻塞了一秒钟。

在 foo 被阻塞的时候,setInterval 仍然在组织将来对回调函数的调用。 因此,当第一次 foo 函数调用结束时,已经有 10 次函数调用在等待执行。

但是实际上我测试的时候foo的调用也是并发(setInterval方法导致)的,就是说每次foo被调用之间相隔100毫秒,而不是1.1秒,并不会因为你前面的foo阻塞了1秒,后面的setInterval方法调用foo的时候就会等你1秒.感觉和书上的说法有点出入..也有可能是我理解错书上的意思了...

3.处理可能的阻塞调用

最简单也是最容易控制的方案,是在回调函数内部使用 setTimeout 函数。

 function foo(){
// 阻塞执行 1 秒
setTimeout(foo, 100);
}
foo();

这样的话相当阻塞的时候不会计算setTimeout时间..

4.隐藏使用 eval

setTimeout 和 setInterval 也接受第一个参数为字符串的情况。 这个特性绝对不要使用,因为它在内部使用了 eval

 function foo() {
// 将会被调用
} function bar() {
function foo() {
// 不会被调用
}
setTimeout('foo()', 1000);
}
bar();

由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo

上面那种情况一般不会发生,但是下面这种情况是可能的.

 function foo(a, b, c) {}

 // 不要这样做
setTimeout('foo(1,2, 3)', 1000) // 可以使用匿名函数完成相同功能
setTimeout(function() {
foo(1, 2, 3);
}, 1000)

JavaScript 秘密花园 学习心得的更多相关文章

  1. JavaScript Date 学习心得

    1.要创建一个日期对象,使用new 操作符和Date构造函数即可: var date=new Date() 在调用Date构造函数而不传递参数的情况下,新创建的对象可以自动获得当前日期和时间.必须传入 ...

  2. JavaScript学习心得

    javaScript十分的强大,所以自然而然学起来也是不易的,想要掌握它的核心,把它理解透更是不易的,但只要你能够静下心来,耐心的去钻研,学习,还是可以把它给学好的,加油吧! 下面是一些JavaScr ...

  3. 我JSP学习心得1

    老师布置了一项作业,说是要按着老师的要求写,但我觉得只要是技术分享的心得就是好的,不论是不是所要求的内容. 由于和几个人在外面给别人搭建网站,项目需要学习了jsp有用到了javascript,这里有一 ...

  4. fullpage 插件学习心得

    fullpage.js 是一个基于jquery 的插件,它能够轻松的制作出高大上的全屏网站,主要功能有; 1.支持鼠标滚动 2.支持前进后退和键盘控制 3.多个回调函数 4.支持 CSS3 动画 5. ...

  5. Ajax学习心得

    Ajax学习心得 大致学了下Ajax,才知道它不是某种编程语言,而是一种在无需加载整个页面的情况下能够更新部分网页的技术.了解了它的功能后觉得这真是一种好的技术,这得给前端和运维省多少力啊! 传统的网 ...

  6. jquery validate学习心得

    据说,javascript最初的由来就是为了解决表单的验证问题,当然现在的js已经能够用来做各种各样炫酷的效果,不过表单验证一直以来都是js很重要的一个用途(在博客园第一篇博客,不知道说些什么开头~~ ...

  7. css3 3d学习心得

    css3 3d学习心得 卡片反转 魔方 banner图 首先我们要学习好css3 3d一定要有一定的立体感 通过这个图片应该清楚的了解到了x轴 y轴 z轴是什么概念了. 首先先给大家看一个小例子: 卡 ...

  8. PWA学习心得

    PWA学习心得 一.什么是PWA Progressive  Web  App , (渐进式增强 WEB 应用) 简称 PWA ,是提升WebApp的体验的一种新方法,能给用户原生应用的体验. PWA ...

  9. Javascript的学习清单

    Javascript的学习清单 Javascript学习资源 程序员必读书籍 深入理解JavaScript系列 es6教程 jQuery中文文档 vue官网 zeptojs中文版 常用的插件与UI组件 ...

随机推荐

  1. ORA-00600 3020 ORA-10567案例

    PlateSpin克隆复制出的Oracle数据库服务器,往往启动数据库实例都会遇到一些杂七杂八的问题.今天测试DR环境时又遇到了一个特殊场景,在此之前,我已经遇到了下面两起案例: ORA-00600: ...

  2. mysql半同步复制问题排查

    1.问题背景      默认情况下,线上的mysql复制都是异步复制,因此在极端情况下,主备切换时,会有一定的概率备库比主库数据少,因此切换后,我们会通过工具进行回滚回补,确保数据不丢失.半同步复制则 ...

  3. RabbitMQ 高可用集群搭建及电商平台使用经验总结

    面向EDA(事件驱动架构)的方式来设计你的消息 AMQP routing key的设计 RabbitMQ cluster搭建 Mirror queue policy设置 两个不错的RabbitMQ p ...

  4. Mac上安装MySQL记录

    下载最新的MySQL社区版 官方下载地址:http://dev.mysql.com/downloads/mysql/ 为了安装更方便,建议下载dmg安装包. 最新的版本是5.7.9. 安装MySQL ...

  5. head/tail实现

         只实现了head/tail的基本功能,默认显示十行及-n参数.       一.使用带缓冲的系统调用.       write/read等系统调用是不带缓冲的,可以包装一层,使其带缓冲. t ...

  6. 解决mybatis foreach 错误: Parameter '__frch_item_0' not found

    解决mybatis foreach 错误: Parameter '__frch_item_0' not found 在遍历对象的属性(是ArrayList对象)时报错: org.mybatis.spr ...

  7. python学习4

    1.python中的函数的参数,这个参数的设置比起C比较特殊的地方就是参数可以预保留的.这个意思就是可以保留下来不填写,然后需要的时候再传入. 这个调用之后结果如下,另外可以看出python比起C来一 ...

  8. [LeetCode] Logger Rate Limiter 记录速率限制器

    Design a logger system that receive stream of messages along with its timestamps, each message shoul ...

  9. [LeetCode] Insertion Sort List 链表插入排序

    Sort a linked list using insertion sort. 链表的插入排序实现原理很简单,就是一个元素一个元素的从原链表中取出来,然后按顺序插入到新链表中,时间复杂度为O(n2) ...

  10. Node中的定时器详解

    在大多数的业务中,我们都会有一些需求,例如几秒钟实现网页的跳转,几分钟对于后台数据进行清理,node与javascript都具有将代码延迟一段时间的能力.在node中可以使用三种方式实现定时功能:超时 ...