Code Monkey home page Code Monkey logo

articles's Introduction

articles's People

Contributors

allenleeok avatar

Stargazers

 avatar

Watchers

James Cloos avatar  avatar

articles's Issues

由JS继承想到的

借用构造函数

创建一个名为Parents构造函数

function Parents(name){
  this.name = name;
  this.sayName = function(){
    console.log(this.name);
  }
}

创建一个名为Children的构造函数,用来继承Parents的属性

function Children(name){
  Parents.call(this, name);   // allen
}

创建实例对象,并调用sayName方法

var child = new Children('allen');
child.sayName();

这里我们修改一下Children,看看会输出什么

function Children(name){
  // Parents.call(this, name);  //allen
  // Parents.call(this, arguments);  //{ '0': 'allen' }
  // Parents.call(this, Array.prototype.slice.call(arguments));  //[ 'allen' ]
  // Parents.apply(this, name);  //报错
  // Parents.apply(this, [name])  //allen
  // Parents.apply(this, arguments)  //allen
  Parents.apply(this, Array.prototype.slice.call(arguments));  //allen
}

参照apply和call方法的区别,上面的结果就显而易见了。
如果我们把Children的参数修改为rest参数,结果就会有新的不同

写累了,未完待续。。。

传递引用

JavaScript总是按值传递,但对于对象,变量的值是引用。因此,当你传递对象并更改其成员时,这些更改将保留在该函数之外。这使它看起来像通过引用传递。但是,如果你实际更改了对象变量的值,您将看到更改不会持续存在,从而证明它确实是通过值传递的。

function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

changeStuff(num, obj1, obj2);

console.log(num); // 10
console.log(obj1.item); // changed
console.log(obj2.item); // unchanged

深拷贝

递归的实现方式

function deepCopy(obj, hash = new WeakMap()) {
  function isObj(obj) {
    return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
  }

  let cloneObj;
  let Constructor = obj.constructor;
  switch (Constructor) {
    case RegExp:
      cloneObj = new Constructor(obj);
      break;
    case Date:
      cloneObj = new Constructor(obj.getTime());
      break;
    default:
      if (hash.has(obj)) return hash.get(obj);
      cloneObj = new Constructor();
      hash.set(obj, cloneObj);
  }
  for (let key in obj) {
    cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key];
  }
  return cloneObj;
}

宽松相等和严格相等

宽松相等(抽象相等)== 和严格相等 === 正确的解释:

"==" 允许在相等比较中进行强制类型转换,而 "===" 不允许

抽象相等

规则:

  • 如果两个值的类型相同,就仅比较它们是否相等。
    有几个非常规的情况需要注意。
    • NaN 不等于 NaN。
    • +0 等于 -0。
  • 对象(包括函数和数组)的宽松相等 ==。两个对象指向同一个值时
    即视为相等,不发生强制类型转换。
  • 在比较两个不同类型的值时会发生隐式强制类型转换,会将其中之一或两者都转换为相同的类型后再进行比较。

比较:

  1. 字符串和数字之间的相等比较:
    字符串被强制类型转换为数字以便进行相等比较。
     
  2. 其他类型和布尔类型之间的相等比较:
    布尔类型被强制类型转换为数字,然后进行下一步判断。
     
  3. null 和 undefined 之间的相等比较:
    (1) 如果 x 为 null,y 为 undefined,则结果为 true。
    (2) 如果 x 为 undefined,y 为 null,则结果为 true。
     
  4. 对象和非对象之间的相等比较:
    (1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
    (2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。

注: ToPrimitive 抽象操作的所有特性(如 toString()、valueOf()) 在这里都适用。

ToPrimitive

ToPrimitive 运算符接受一个值,和一个可选的 期望类型 作参数。ToPrimitive 运算符把其值参数转换为非对象类型。如果对象有能力被转换为不止一种原语类型,可以使用可选的 期望类型 来暗示那个类型。

对Object进行ToPrimitive()操作: 返回该对象的默认值。对象的默认值由把期望类型传入作为hint参数调用对象的内部方法[[DefaultValue]]得到。

[[DefaultValue]] (hint)

  • 传入的hint是String,先判断toString能否调用,再判断toString()的结果,是基本类型才返回,再判断valueOf能否调用,再判断valueOf()的结果,是基本类型才返回,否则报错。
  • 传入的hint是Number(或者没有hint,默认是Number),先判断valueOf,再判断toString
  • 普通Object,默认用hint为Number的方式来转换,对于Date类型的Object,用hint为String的方式来转换

例子

"0" == ""   // false
"0" == []   // false

false == ""   // true
false == ""   // true
false == []   // true
false == {}  // false

"" == 0    //true
"" == []   // true
"" == {}  // false

0 == []   // true
0 == {}   // false

比较特殊的情况

更改内置原生原型

  • 返回其他数字
Number.prototype.valueOf = function() {
 return 3;
};
new Number( 2 ) == 3;   // true

参考

http://yanhaijing.com/es5/#203
http://yanhaijing.com/es5/#103
http://yanhaijing.com/es5/#100
https://zhuanlan.zhihu.com/p/29730094

JS代码优化

块级作用域

用let将变量附加在一个已经存在的块作用域上的行为是隐式的,为块作用域显式地创建块使变量的附属关系变得更加清晰

var foo = true;

if (foo) {
  { // <-- 显式的块
    let bar = foo * 2;
    bar = something( bar );
    console.log( bar );
  }
}

console.log( bar ); // ReferenceError

垃圾收集

click函数形成了一个覆盖整个作用域的闭包,块作用域可以让引擎知道没有必要继续保存someReallyBigData

function process(data) {
  // 在这里做点有趣的事情
}

// 在这个块中定义的内容完事可以销毁!
{
  let someReallyBigData = { .. };
  process( someReallyBigData );
}

var btn = document.getElementById( "my_button" );

btn.addEventListener( "click", function click(evt){
  console.log("button clicked");
}, /*capturingPhase=*/false );

类型

内置类型

null

使用typeof来查看null的类型有问题。

typeof null === "object"; // true

 
我们需要使用复合条件来检测 null 值的类型:

var a = null;
(!a && typeof a === "object"); // true

null 是基本类型中唯一的一个“假值”,typeof
对它的返回值为 "object"。

function

typeof function a(){} === "function"; // true

函数是“可调用对象”,它有一个内部属 性 [[Call]],该属性使其可以被调用。
函数对象的 length 属性是其声明的参数的个数:

a.length; // 2

因为该函数声明了两个命名参数,b 和 c,所以其 length 值为 2。

array

typeof [1,2,3] === "object"; // true

数组也是对象。确切地说,它也是 object 的一个“子类型”,数组的 元素按数字顺序来进行索引(而非普通像对象那样通过字符串键值),其 length 属性是元素的个数。

值和类型

typeof 运算符总是会返回一个字符串:

typeof typeof 42; // "string"

undefined 和 undeclared

var a;
typeof a; // "undefined"
typeof b; // "undefined"

对于 undeclared(或者 not defined)变量,typeof 照样返回 "undefined"。请注意虽然 b 是 一个undeclared变量,但typeof b并没有报错。这是因为typeof有一个特殊的安全防范机制(不会报错)。

Scheme编程环境搭建

安装 Emacs

安装 homebrew 后,执行 "brew cask install emacs" 命令,emacs默认的配置文件夹是 .emace.d,在该文件夹新建文件 init.el

配置 MELPA 源

在 init.el 文件中添加以下代码

(require 'package)

(let* ((no-ssl (and (memq system-type '(windows-nt ms-dos))
                    (not (gnutls-available-p))))
       (url (concat (if no-ssl "http" "https") "://melpa.org/packages/")))
  (add-to-list 'package-archives (cons "melpa" url) t))
(when (< emacs-major-version 24)
  ;; For important compatibility libraries like cl-lib
  (add-to-list 'package-archives '("gnu" . "http://elpa.gnu.org/packages/")))

(package-initialize)

安装 scheme

Chez Scheme

执行 "brew install chezscheme" 命令,安装 Chez Scheme 解释器

设置ParEdit mode

  1. 打开scheme,执行 "M-x package-install paredit " 命令, 安装 ParEdit。
  2. 在 init.el 文件中添加一下代码, 使得emacs在启动后就自动加载 paredit-mode 模式
(autoload 'enable-paredit-mode "paredit" "Turn on pseudo-structural editing of Lisp code." t)
    (add-hook 'emacs-lisp-mode-hook       #'enable-paredit-mode)
    (add-hook 'eval-expression-minibuffer-setup-hook #'enable-paredit-mode)
    (add-hook 'ielm-mode-hook             #'enable-paredit-mode)
    (add-hook 'lisp-mode-hook             #'enable-paredit-mode)
    (add-hook 'lisp-interaction-mode-hook #'enable-paredit-mode)
    (add-hook 'scheme-mode-hook           #'enable-paredit-mode)

设置 scheme mode

这里参考了王垠大大的文章,在 init.el 文件中添加以下代码,配置会在加载 Scheme 文件的时候自动载入 ParEdit mode,并且把 F5 键绑定到“执行前面的S表达式”。这样设置的目的是,我只要把光标移动到一个S表达式之后,然后用一根手指头按 F5,就可以执行程序(懒人福音,比如我)

;;; 手动将你的 Chez 或其他 Scheme 实现的 $PATH 变量加入到 Emacs 中
(add-to-list 'exec-path "/usr/local/bin")
;;; 调整一下默认的 scheme-mode
(setq scheme-program-name "chez")

;;;;;;;;;;;;
;; Scheme 
;;;;;;;;;;;;

(require 'cmuscheme)
(setq scheme-program-name "chez")

;; bypass the interactive question and start the default interpreter
(defun scheme-proc ()
  "Return the current Scheme process, starting one if necessary."
  (unless (and scheme-buffer
               (get-buffer scheme-buffer)
               (comint-check-proc scheme-buffer))
    (save-window-excursion
      (run-scheme scheme-program-name)))
  (or (scheme-get-process)
      (error "No current process. See variable `scheme-buffer'")))

(defun scheme-split-window ()
  (cond
   ((= 1 (count-windows))
    (delete-other-windows)
    (split-window-vertically (floor (* 0.68 (window-height))))
    (other-window 1)
    (switch-to-buffer "*scheme*")
    (other-window 1))
   ((not (cl-find "*scheme*"
               (mapcar (lambda (w) (buffer-name (window-buffer w)))
                       (window-list))
               :test 'equal))
    (other-window 1)
    (switch-to-buffer "*scheme*")
    (other-window -1))))

(defun scheme-send-last-sexp-split-window ()
  (interactive)
  (scheme-split-window)
  (scheme-send-last-sexp))

(defun scheme-send-definition-split-window ()
  (interactive)
  (scheme-split-window)
  (scheme-send-definition))

(add-hook 'scheme-mode-hook
  (lambda ()
    (paredit-mode 1)
    (define-key scheme-mode-map (kbd "<f5>") 'scheme-send-last-sexp-split-window)
    (define-key scheme-mode-map (kbd "<f6>") 'scheme-send-definition-split-window)))

Iterator and Observable

迭代器实现

String.prototype[Symbol.iterator] = function (value) {
  var nextIndex = 0;
  var _this = this;
  return {
    next: function() {
      return nextIndex < _this.length ?
        {value: _this[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}

var someString = 'hi';
console.log([...someString]);

linux常用命令

列出所有shell的路径: cat /etc/shells
切换默认终端 chsh -s /bin/zsh

作用域和闭包

隐藏内部实现

function doSomething(a) { 
  function doSomethingElse(a) {
    return a - 1; 
  }
  var b;
  b = a + doSomethingElse( a * 2 );
  console.log( b * 3 );
}
doSomething( 2 ); // 15

函数作用域

区分函数声明和表达式最简单的方法是看 function 关键字出现在声明中的位 置(不仅仅是一行代码,而是整个声明中的位置)。如果 function 是声明中 的第一个词,那么就是一个函数声明,否则就是一个函数表达式。

循环和闭包

for (var i=1; i<=5; i++) { 
  setTimeout( function timer() {
    console.log( i ); // 5
  }, i*1000 );
}

// 需要有自己的变量,用来在每个迭代中储存 i 的值
for (var i=1; i<=5; i++) { 
  (function(j) {
    setTimeout( function timer() { console.log( j );
  }, j*1000 ); })(i);
}

// 块作用域和闭包
for (let i=1; i<=5; i++) { 
  setTimeout( function timer() {
    console.log( i );
  }, i*1000 );
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.