JavaScript设计模式读书笔记----字面量和构造函数,函数

  1. 当以 new 操作符调用构造函数时, 函数内部将会发生以下变化:

    创建一个空对象并且 this 变量引用了该对象,同时还继承了该函数的原型;
    属性和方法被加入到 this 引用的对象中;
    新创建的对象由 this 引用,并且最后隐式的返回 this ;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var Person = function (name) {
    //使用对象字面量模式创建一个新对象
    var this = {} ;
    //向this添加属性和方法
    this.name = name;
    this.say = function () {
    return "I'm" + this.name;
    }
    //return this;
    };
    //一般情况下,将一个方法添加到Person的原型
    Person.prototype.say = function () {
    return "I'm" + this.name;
    }
  2. 当使用new操作符创建对象时,构造函数总是返回一个对象。默认返回this所引用的对象,将返回空;

  3. 检测数组的方法 :

    1
    2
    3
    4
    5
    6
    if ( typeof Array.isArray === "undefined" ) {
    Array.isArray = function (arg) {
    //调用Object.prototype.toString()的call()方法, 如果是数组返回[object Array],对象返回[Object Object]
    retrun Object.prototype.toString.call(arg) === "[object Array]";
    };
    }
  4. 函数的提升

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function foo () {
    alert("global foo");
    }
    function bar () {
    alert("global bar");
    }
    function hoistMe()
    console.log(typeof foo); // "function"
    console.log(typeof bar); //"undefined"
    foo(); // "global foo"
    bar(); // TypeError: bar is not a function
    //函数声明,变量"foo"及其实现者被提升
    function foo () {
    alert("local foo");
    }
    //函数表达式,仅变量"bar"被提升,函数实现并未被提升
    var bar = function () {
    alert("local bar");
    };
    }
    hoistMe();
  5. 异步事件监听器

    1
    document.addEventListener("click",function(){alert("hello~")},false);
  6. 即时函数
    即时函数模式(Immediate Function pattern)是一种可以支持在定义函数后立即执行该函数的语法。

    1
    2
    3
    4
    5
    (function () {
    alert("looooooook!");
    }());
    //在函数末尾添加一组括号,这导致该函数立刻执行
    //将所有代码包装到它的局部作用域中,切不会将任何变量泄露到全局作用域之中
  7. 即时函数的返回值
    可以利用即时函数包装一个在对象生存期内不会改变的属性,并且即时函数的返回值会成为属性值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var o = {
    message: (function(){
    var who = "me",
    what = "call";
    return what+" "+who;
    }()),
    getMsg: function () {
    return this.message;
    }
    };
    o.getMsg(); //输出"call me"
    o.message; //输出"call me"
  8. 即时函数的初始化

    1
    2
    3
    ({...}).init();
    ({...}.init());
    //如果要在init()结束后保存对该对象的一个引用,可以通过在init()后面添加"return this"实现该功能;
  9. 备忘模式
    函数 myFunc 创建了一个属性cache,cache属性是一个对象(哈希对象),使用传递给函数的param作为键,结果为值。

    1
    2
    3
    4
    5
    6
    7
    8
    var myFunc = function () {
    if ( !myFunc.cache[param] ) {
    //一些操作
    var result = {};
    myFunc.cache[param] = result;
    }
    return myFunc.cache[param];
    }
  10. 配置对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //before
    function addPerson (name,age,birth,address,gender,first,last){......};
    addPerson("begin","16",'123","女","b","g");
    //after
    var conf = {
    name:"begin",
    first:"b",
    last::"g",
    gender:"女"
    };
    addPerson(conf);

优点:不需要记住众多的参数及其顺序,可以安全忽略可选参数,易于阅读和维护,易于添加和删除参数。

  1. call()和apply()的区别
    http://www.jianshu.com/p/3a823ef9db97

  2. Curry化 //需要深入了解
    当新函数是基于现有函数,并加上部分参数列表创建时。

总结:

  1. API 模式:
    • 回调模式:将函数作为参数进行传递
    • 配置对象:便于控制函数的参数数量
    • 返回函数:当一个函数的返回值是另一个函数时
    • Curry化:当新函数是基于现有函数,并加上部分参数列表创建时
  2. 初始化模式
    • 即时函数 :定义后立即的函数
    • 即时对象初始化:匿名对象组织了初始化任务,提供了可以被立即调用的方法
    • 初始化时分支:帮助分支代码在初始化时仅检测一次
  3. 性能模式
    • 备忘模式:使用函数属性以便计算过的值无需再次计算
    • 自定义模式:以新的主体重写本身,使得后续调用时进行的工作更少

JavaScript设计模式读书笔记----基本技巧

  1. 编写可维护的代码
  2. 尽量减少全局变量

    没有声明或没有对链式赋值的所有变量进行声明时也生成全局变量
    隐含全局变量可以通过delete删除,明确定义的全局变量则不可以。隐含全局变量是全局对象的属性。

  3. 不要增加内置对象的原型。
  4. 优化 for 循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //一般情况
    for( var i = 0;i < arr.length ; i++ ) {
    //处理 arr[i]
    }
    //但是每次访问任何容器的长度时,都是在查询活动的 DOM ,应该减少这种 DOM 操作
    //优化之后
    var length = arr.length ;
    for( var i = 0;i < length ; i++ ) {
    //处理 arr[i]
    }
    //最优
    var i,arr = [];
    for ( i = arr.length ; i-- ) { //使用最少的变量;逐步减至0,因为与0比较比与数组长度比较更有效率
    //处理 arr[i]
    }
    //或使用 while 循环
    var arr = [];
    i = arr.length;
    while ( i-- ) {
    //处理 arr[i]
    }
  5. for-in

    1
    2
    3
    4
    5
    for ( var i in man ) {
    if ( man.hasOwnProperty(i)) {
    console.log(i);
    }
    }
  6. 不要使用setInterval( ),setTimeout( )等构造函数来传递参数。

  7. 不要使用 eval( ), 可以使用 new Function ( ) 来替代或将 eval( ) 封装在一个即时函数中
    //eval( )会影响到作用域链,可以访问和修改它外部作用域的变量
  8. 字符串转化为数字的方法:

    1
    2
    3
    parseInt("08",10) //注意一定要给第二个参数赋值
    +"08" // 8
    Number("08"); //8
  9. 命名约定

    构造函数的首字母大写
    变量名和函数名采用驼峰命名法
    大写的变量名约定该变量在程序生命周期中不可改变
    JSLint 会对下划线前缀给出警告

京东笔试整理

记录一下前几天京东笔试遇到的一些问题:

  • 对于 history 对象的理解
    history.forward() 方法加载历史列表中的前一个 URL。
    history.back() 方法加载历史列表中的后一个 URL。
    window.history.go(-1) 是返回上一页
    window.location.go(-1) 是刷新上一页

  • css属性选择器
    *[lang|=”en”] {color: red;}
    会选取所有 lang 属性等于 en 或以 en 开头的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
[[*attribute*]] 用于选取带有指定属性的元素。
[[*attribute*=*value*]] 用于选取带有指定属性和值的元素。
[[*attribute*~=*value*]] 用于选取属性值中包含指定词汇的元素。
[[*attribute*|=*value*]] 用于选取带有以指定值开头的属性值的元素,该值必须是整个单词。
[[*attribute*^=*value*]] 匹配属性值以指定值开头的每个元素。
[[*attribute*$=*value*]] 匹配属性值以指定值结尾的每个元素。
[[*attribute**=*value*]] 匹配属性值中包含指定值的每个元素。
  • C++位移运算
    & 对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
1
2
3
4
5
6
int x = 2014 ;
int count = 0 ;
while ( x ) {
x & ( x-1 ) ;
count ++ ;
}

结束循环时,x 应当为10
2014 的二进制为 11-1101-1110
2015 的二进制为 11-1101-1101
移位之后为 11-1101-1100
减一 11-1101-1011
二次移位之后 11-1101-1000
……
所以 count 的值为10

  • redhat

  • 顺序查找

  • 希尔排序

点滴云开发

线上地址:http://123.56.195.73/
1.webpack.base.config中,

1
2
3
4
5
6
7
8
9
10
output: {
path:path.resolve(__dirname,'../dist/static'), //会build时在css和js之前加dist/static路径
publicPath:'/static/', //build时会自动在图片文件之前加static路径
filename:'[name].js'
}

2.vue内的js需要

1
2
3
4
5
6
<script type='text/ecmascript-6'></script>
export default{
}

3.页面跳转会固定跳转到之前页面的位置,要加下面一行代码才行

1
2
3
4
5
6
router.beforeEach(function() {
window.scrollTo(0,0)
})

4.最新版本的vue在app.vue中必须return一个参数,否则build出的静态页面会报错。

5.如何使元素静止时是1px 的border,当鼠标hover时是3px的border而不引起元素浮动?

答 :在平时设置3px颜色为transparent的border。如果要变圆角,则加overflow:hidden

6.stylus media query

答:

1
2
3
4
5
6
7
8
@mediascreenand(max-width:320px)
#content //注意层级关系
ul
width 85%

7.ios和OX渲染input时会默认在内部加上padding,导致同等height的button和input看起来并不相等;input会默认加border-radius

8.跑mongodb时会出现的错误:

Unable to create/open lock file: /data/mongod.lock errno:13 Permission denied

使用

$ sudo mkdir -p /data/db/

$ sudo chown USERNAME /data/db

通过 whoami 获取USERNAME

指定dbpath 启动 ./mongod –dbpath /data/dbv

首页效果:
移动端效果:

jQuery-ajax

想了解一下jQuery是如何封装Ajax的,在网上找到了下面的代码(一种类似jQuery的实现方式)。
读了源码,加了注释。

ajax.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
(function(exports, document, undefined){
"use strict";
function Ajax(){
if(!(this instanceof Ajax)) return;
return this;
}
Ajax.prototype = {
init: function(opts){
opts = opts || {};
this.opts = opts;
this.opts.type = opts.type || 'get'; //若没有设定type类型则默认GET
this.opts.url = opts.url || '';
this.opts.data = opts.data || '';
this.opts.dataType = opts.dataType || 'text';
this.opts.async = opts.async || true;
this.opts.success = opts.success || null;
this.opts.error = opts.error || null;
this.xhr = this.createXMLHttpRequest.call(this);
this.initEvent.call(this);
return this;
},
ajax: function(opts){
this.init.apply(this, arguments); //扩充作用域
this.open.call(this);
this.send.call(this);
},
createXMLHttpRequest: function(){
var xhr;
try{
xhr = new XMLHttpRequest();
}catch(e){
console.log(e);//捕获错误
}
return xhr;
},
initEvent: function(){
var _this = this;
this.xhr.onreadystatechange = function(){
if(_this.xhr.readyState == 4 && _this.xhr.status == 200){
if(_this.xhr.status == 200){
if(_this.opts.dataType === 'text' || _this.opts.dataType === 'TEXT'){
_this.opts.success && _this.opts.success(_this.xhr.responseText, 'success', _this.xhr);
//若dataType为text,则返回内容为Text
}else if(_this.opts.dataType === 'xml' || _this.opts.dataType === 'XML'){
_this.opts.success && _this.opts.success(_this.xhr.responseXML, 'success', _this.xhr);
//若dataType为text,则返回内容为XML
}else if(_this.opts.dataType === 'json' || _this.opts.dataType === 'JSON'){
//若dataType为json,则返回内容为JSON
_this.opts.success && _this.opts.success(JSON.parse(_this.xhr.responseText), 'success', _this.xhr);
}
}else if(_this.xhr.status != 200){
//若status不为200,则报错
_this.opts.error && _this.opts.error(_this.xhr, 'error');
}
}
}
},
open: function(){
if(this.opts.type === 'GET' || this.opts.type === 'get'){
var str = (typeof this.opts.data === 'string') && this.opts.data || this.objectToString.call(this, this.opts.data),
url = (str === '') && this.opts.url || (this.opts.url.split('?')[0] + '?' + str);
//GET方法下,若不传参则url不变;若传参,则其参数会被data替代
this.xhr.open(this.opts.type, url, this.opts.async);
}else if(this.opts.type === 'POST' || this.opts.type === 'post'){
//POST方法下,url则为问号分隔符前面的部分;
this.xhr.open(this.opts.type, this.opts.url.split('?')[0], this.opts.async);
}
return this;
},
send: function(){
if(this.opts.type === 'GET' || this.opts.type === 'get'){
this.xhr.send();
}else if(this.opts.type === 'POST' || this.opts.type === 'post'){
//若POST参数为string,则传参;若不是,则将通过objectToString函数将object转化为string;
var str = (typeof this.opts.data === 'string') && this.opts.data || this.objectToString.call(this, this.opts.data);
this.xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
this.xhr.send(str);
}
},
objectToString: function(data){
if(typeof data !== 'object') return data;
var str = '';
for(var prop in data){
//遍历data,将其中的元素用&分开且练成字符串
str += '&' + prop + '=' + data[prop];
}
return str.slice(1);
}
}
exports.Ajax = Ajax; //将Ajax方法导出;
})(window, document);

通过json-server搭建后台数据;
(这个环境用于测试超级方便~)

使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax</title>
</head>
<body>
<script src="ajax.js"></script>
<script>
new Ajax().ajax({
type: 'get',
url: 'http://localhost:3000/db?c=123',
// data: 'c=456',
// data: {c: 456},
dataType: 'json',
async: false,
success: function(data, status, xhr){
console.log(data);
},
error: function(xhr, status){
console.log(xhr);
}
});
new Ajax().ajax({
type: 'post',
url: 'http://localhost:3000/db?c=123',
data: 'c=456',
// data: {c: 456},
dataType: 'text',
success: function(data, status, xhr){
console.log(data);
},
error: function(xhr, status){
console.log(xhr);
}
});
</script>
</body>
</html>

原生Ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var xhr = new createXHR();
xhr.onreadystatechange = function (){
if(xhr.readyState == 4){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status ==304 ){
console.log(xhr.responseText);
}else{
console.log("error"+xhr.status);
}
}
};
//get请求
xhr.open('get','url',true);
xhr.setRequestHeader("header","hello");
xhr.send(null);
//post请求
xhr.open('post','url',true);
xhr.setRequstHeader("Content-Type","application/x-www-form-urlencoded");
var form = document.getElementById('form');
//用serialize将表单序列化,创建字符串
xhr.send(serialize(form));
//FormData
var form = document.getElementById('form');
xhr.send(new FormData(form));
//此外还有load,progress等进度事件

浏览器渲染机制

一.加载

浏览器的五个常驻线程:

  1. 浏览器 GUI 渲染线程

  2. javascript 引擎线程

  3. 浏览器定时器触发线程( setTimeout,setInterval )

  4. 浏览器事件触发线程

  5. 浏览器 http 异步请求

当js引擎线程(第二个)进行时,会挂起其他一切线程,这个时候3、4、5这三类线程也会产生不同的异步事件,由于 javascript引擎线程为单线程,所以代码都是先压到队列,采用先进先出的方式运行,事件处理函数,timer函数也会压在队列中,不断的从队头取出事件,这就叫:javascript-event-loop。简单点说应该是当在进行第二线程的时候,1,3,4,5都会挂起,比如这时候触发click事件,即使先前JS已经加载完成,click事件会压在队列里,这里也要先完成第二线程才会执行click事件。

加载顺序:http://www.cnblogs.com/web-easy/p/5067680.html

二、渲染

渲染引擎的职责,就是负责把从服务器返回HTML,XML或者images等资源渲染并展现给用户。

常用的渲染引擎有:webkit ( chrome, safari, opera ) 和 gecko ( firefox )。

基本的渲染过程:

  1. 渲染引擎首先会解析 HTML 文档,转化为 DOM 树。

  2. 解析 CSS 的样式,渲染出另外一棵用于渲染 DOM 树的 render-tree ,render-tree 中包含有 css 中的颜色,属性等。

  3. 对 render-tree 中的每个节点进行布局,确定其在屏幕上的位置。

  4. 遍历渲染树,将每一个节点绘制出来。

webkit 的渲染流程:

gecko 的渲染流程:

通过上图可以看出,webkit 与 gecko 最大的区别就是渲染样式的时间。

webkit 中,解析 HTML 与 CSS 样式是同时发生的。

而 gecko 中 HTML 解析出 content-sink ( DOM树搭建前的 pre-model ) 之后,按照 pre-model 来解析样式。

关于 content-sink

样式计算优先级:

  1. 浏览器默认样式

  2. 用户个性化浏览器设置

  3. HTML 开发者定义的一般样式

  4. 开发者定义的 !important 样式

  5. 用户个性浏览器设置的 !important 样式

更详细的:

通用选择器(*)>元素(类型)选择器>类选择器>属性选择器>伪类>ID 选择器>内联样式

count 1 if the declaration is from is a ‘style’ attribute rather than a rule with a selector, 0 otherwise (= a)

count the number of ID attributes in the selector (= b)

count the number of other attributes and pseudo-classes in the selector (= c)

count the number of element names and pseudo-elements in the selector (= d)

举例说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
* {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */

上面确定了renderer的样式规则后,然后就是重要的显示因素布局了。当renderer构造出来并添加到render树上之后,它并没有位置跟大小信息,为它确定这些信息的过程,我们就称之为布局。HTML采用了一种流式布局的布局模型,从上到下,从左到右顺序布局,布局的起点是从render树的根节点开始的,对应dom树的document节点,其初始位置为0,0,详细的布局过程为: 每个renderer的宽度由父节点的renderer确定。 父节点遍历子节点,确定子节点的位置(x,y),调用子节点的layout方法确定其高度。 父节点根据子节点的height,margin,padding确定自身的自身的高度。

为了避免因为局部小范围的DOM修改或者样式改变引起整个页面整体的布局重新构造,浏览器采用了一种dirty bit system的技术,使其尽可能的只改变元素本身或者包含的子元素的布局。当然有些情况无可避免的要重新构造整个页面的布局,如适合于整体的样式的改变影响了所有renderer,如body{font-size:111px} 字体大小发生了改变,还有一种情况就是浏览器窗口进行了调整,resize。

参考:

https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity

http://www.cnblogs.com/xugang/archive/2010/09/24/1833760.html

MongoDB基本语句

MongoDB无模式文档型数据库

1.批量插入insert

1
2
3
4
5
db.person.insert([
{name:"Mary", age:21, status:"A"},
{name:"Lucy", age:89, status:"A"},
{name:"Jacky", age:30, status:"A"}
]);

2.文档查询find

1
2
3
4
5
6
7
db.person.find();
db.user.find(
{age:{$gt:18}},
{name:1,address:1}
).limit(5);
db.person.find({status:"X"});//相等条件
db.person.find({age:{$gt:40}});//比较条件

MongoDB运算符:大于$gt,小于$lt,大于等于$gte,小于等于$lte,不等于$ne,包含于$in,不包含于$nin
1
2
3
4
5
6
7
db.person.find({tag:'fruit'});//单个元素匹配
db.person.find({tag.0:'fruit'});//多个元素匹配
db.person.find({"access.level":5});//子文档条件,使用“.key”的方法去访问
//复合查询:
db.person.find({$and:[{type:"food"},{price:{$lt:95}}]});
db.person.find({$and:[{age:{$gt:30}},{name:"Lucy"}]});
db.person.find({$or:[{status:"A"},{age:30}]});

3.文档更新update

1
2
db.collection.update(query,update,{upsert:boolean,multi:boolean})
db.person.update({age:{$lt:30}},{$set:{status:"X"}},{multi:true})//$gt为大于,$lt为小于

4.文档更新save
命令可以更新或插入一个新文档,只能针对一个文档进行操作
db.person.save({name:”Tony”,age:12,gender:”man”});
5.文档移除remove

1
2
3
4
5
6
7
db.collection.remove(
qurey, //boolean类型,删除文档的条件
justOne //为true只删除一个文档,为false则删除所有符合条件的文档
)
db.person.remove(
{status:"D"}
)

6.游标 cursor
find命令并不直接返回结果,而是返回一个结果集的迭代器
想要获得结果,必须使用next方法来遍历游标

1
2
3
4
5
6
7
8
9
var myCursor = db.person.find({status:"A"});
var myDocument = myCursor.hasNext()?myCursor.next():null;
if(myDocument){
var myItem =myDocument.item;
print(tojson(myItme));
}
var myCursor = db.person.find({status:"A"});
myCursor.forEach(printjson);

a)限定条件
limit:设定返回结果集中的最大文档数量;
db.collection.find().limit(Num);
b)结果集
条件:JSON对象,格式=>{字段:值},值为1时表示需要返回,值为0时表示不需要返回
db.person.find({查询条件},{字段条件})
db.person.find({},{name:1});

leetcode-263

Write a program to check whether a given number is an ugly number.

Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7.

Note that 1 is typically treated as an ugly number.

2,3,5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @param {number} num
* @return {boolean}
*/
function isUgly(num) {
if(num == 0) {
return false;
}
while(num % 5 == 0) {
num /= 5;
}
while(num % 3 == 0) {
num /= 3;
}
while(num % 2 == 0) {
num /= 2;
}
if(num == 1) {
return true;
}
return false;
}

leetcode-213

Given an integer, write a function to determine if it is a power of two.

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @param {number} n
* @return {boolean}
*/
function isPowerOfTwo(n) {
if (n%2 != 0 && n != 1) return false;
else if(n < 2 && n != 1) return false;
else if(n == 2) return true;
else if(n == 1) return true;
else
return isPowerOfTwo(n/2);
}

leetcode-202

Write an algorithm to determine if a number is “happy”.

A happy number is a number defined by the following process:Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

Example: 19 is a happy number

12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @param {number} n
* @return {boolean}
*/
function isHappy(n) {
var i=0;
while(n!=1){
var sum =0;
while(n>=10){
sum+=(n%10)*(n%10);
n=Math.floor(n/10);
}
sum+=n*n;
n=sum;
i++;
if(i>5&&sum!=1){
return false;
}
}
return true;
}